自从React/Vue等框架流行之后,jQuery被打上了面条式代码的标签,甚至成了“过街老鼠”,好像谁还在用jQuery,谁就还活在旧时代,很多人都争先恐后地拥抱新框架,各大博客网站有很大一部分的博客都在介绍新的框架,争当时代的“弄潮儿”。新框架带来的新的理念,新的开发方式不可否认带来了生产效率,但是jQuery等就应该被打上“旧时代”面条式代码的标签么?

  我们从一篇文章说起:《React.js 的介绍 – 针对了解 jQuery 的工程师(译)》,英文原文是这个《React.js Introduction For People Who Know Just Enough jQuery To Get By》, 这篇文章我好久前就看过,现在再把它翻出来,里面对比了下jQuery和React分别实现一个发推的功能,作者用jQuery写着写着代码就乱套了,而用React不管需求多复杂,代码条理依旧很清晰。

  我们一步步按照原文作者的思路来拆解。

  (1)输入个数为0时,发送按钮不可点击

  如下图所示,当输入框没有内容时,发推按钮置灰不可点,有内容点才能点。

  作者写的代码是这样的:

  1. // 初始化状态
  2. $("button").prop("disabled", true);
  3. // 文本框的值发生变化时
  4. $("textarea").on("input", function() {
  5. // 只要超过一个字符,就
  6. if ($(this).val().length > 0) {
  7. // 按钮可以点击
  8. $("button").prop("disabled", false);
  9. } else {
  10. //否则,按钮不能点击
  11. $("button").prop("disabled", true);
  12. }
  13. });

  这个代码本身写得很累赘,首先,既然一开始那个button是disabled的,那就直接在html上写个disabled属性就行了:

  1. <form class="tweet-box">
  2. <textarea name="textMsg"></textarea>
  3. <input disabled type="submit" name="tweet" value="Tweet">
  4. </form>

  第二个要控制按钮的状态,其实核心只要一行代码就行了,不需要写那么长:

  1. let form = $(".tweet-box")[0];
  2. $(form.textMsg).on("input", function() {
  3. form.tweet.disabled = this.value.length <= 0;
  4. }).trigger("input");

  这个代码应该够简洁了吧,而且代码在jQuery和原生之间来回切换,游刃有余。

  (2)实现剩余字数功能

  如下图所示:

  这个也好实现:

  1. let form = $(".tweet-box")[0],
  2. $leftWordCount = $("#left-word-count");
  3. $(form.textMsg).on("input", function() {
  4. // 已有字数
  5. let wordsCount = this.value.length;
  6. $leftWordCount.text(140 - wordsCount);
  7. form.tweet.disabled = wordsCount <= 0;
  8. });

  (3)添加图片按钮

  如下图所示,左下角多了一个选择照片的按钮:

  如果用户选择了照片,那么可输入字数将会减少23个字符,并且Add Photo文案要变成Photo Added。我们先来看下作者是怎么实现的,如下代码:

  1. if ($(this).hasClass("is-on")) {
  2. $(this)
  3. .removeClass("is-on")
  4. .text("Add Photo");
  5. $("span").text(140 - $("textarea").val().length);
  6. } else {
  7. $(this)
  8. .addClass("is-on")
  9. .text("✓ Photo Added");
  10. $("span").text(140 - 23 - $("textarea").val().length);
  11. }

  如果代码像作者这样写的话确实是比较乱,而且比较面条式。但是我们可以优雅地实现。首先,选择照片一般会写一个input[type=file]的隐藏输入框盖在上传图标下面:

  1. <div class="upload-container">
  2. <img src="upload-icon.png" alt>
  3. <span id="add-photo">Add Photo</span>
  4. <input type="file" name="photoUpload">
  5. </div>

  然后监听它的change事件,在change事件里面给form套一个类:

  1. $(form.photoUpload).on("change", function() {
  2. // 如果选择了照片则添加一个photo-added的类
  3. this.value.length ? $(form).addClass("photo-added")
  4. // 否则去掉
  5. : $(form).removeClass("photo-added");
  6. });

  然后就可以来实现文案改变的需求了,把上面#add-photo的span标签添加两个data属性,分别是照片添加和未添加的文案,如下代码所示:

  1. <span id="add-photo" data-added-text="Photo Added"
  2. data-notadded-text="Add Photo"></span>

  通过form的类结合before/after伪类控制html上的文案,如下代码所示:

  1. #add-photo:before {
  2. content: attr(data-empty-text);
  3. }
  4. form.photo-added #add-photo:before {
  5. content: attr("data-added-text);
  6. }

  这样就可以了,我们算是用了一个比较优雅的方式实现了一个文案变化的功能,其中CSS的attr可以兼容到IE9,并且这里html/css/js相配合,共同完成这个变化的功能,这应该也挺好玩的。

  剩下一个要减掉23字符的需求,只需要在减掉的时候判断一下:

  1. $(form.textMsg).on("input", function() {
  2. // 已有字数
  3. let wordsCount = this.value.length;
  4. form.tweet.disabled = wordsCount <= 0;
  5. $leftWordCount.text(140 - wordsCount -
  6. //如果已经添加了图片再减掉23个字符
  7. ($(form).hasClass("photo-added") ? 23 : 0));
  8. });

  然后在选择图片之后trigger一下,让文字发生变化,如下代码倒数第二行:

  1. /*
  2. * @trigger 会触发文字输入框的input事件以更新剩余字数
  3. */
  4. $(form.photoUpload).on("change", function() {
  5. // 如果选择了照片则添加一个photo-added的类
  6. this.value.length ? $(form).addClass("photo-added") :
  7. // 否则去掉
  8. $(form).removeClass("photo-added");
  9. $(form.textMsg).trigger("input");
  10. });

  这里又使用了事件的机制,用reac应该基本上都是用状态state控制了。

  再来看最后一个功能。

  (4)没有文字但是有照片发推按钮要可点

  上面是只要没有文字,那么发推按钮不可点,现在要求有图片就可点。这个也好办,因为如果有图片的话,form已经有了一个类,所以只要再加一个判断就可以了:

  1. $(form.textMsg).on("input", function() {
  2. // 已有字数
  3. let wordsCount = this.value.length;
  4. form.tweet.disabled = wordsCount <= 0
  5. //disabled再添加一个与判断
  6. && !$(form).hasClass("photo-added");
  7. $leftWordCount.text(140 - wordsCount -
  8. //如果已经添加了图片再减掉23个字符
  9. ($(form).hasClass("photo-added") ? 23 : 0));
  10. });

  最后看一下,汇总的JS代码,加上空行和注释总共只有23行:

  1. let form = $(".tweet-box")[0],
  2. $leftWordCount = $("#left-word-count");
  3. $(form.textMsg).on("input", function() {
  4. // 已有字数
  5. let wordsCount = this.value.length;
  6. form.tweet.disabled = wordsCount <= 0
  7. //disabled再添加一个与判断
  8. && !$(form).hasClass("photo-added");
  9. $leftWordCount.text(140 - wordsCount -
  10. //如果已经添加了图片再减掉23个字符
  11. ($(form).hasClass("photo-added") ? 23 : 0));
  12. });
  13. /*
  14. * @trigger 会触发文字输入框的input事件以更新剩余字数
  15. */
  16. $(form.photoUpload).on("change", function() {
  17. // 如果选择了照片则添加一个photo-added的类
  18. this.value.length ? $(form).addClass("photo-added") :
  19. // 否则去掉
  20. $(form).removeClass("photo-added");
  21. $(form.textMsg).trigger("input");
  22. });

  html大概有10行,还有6行核心CSS,不过这两个比较易读。再来看一下React的完整版本,作者的实现:

  1. var TweetBox = React.createClass({
  2. getInitialState: function() {
  3. return {
  4. text: "",
  5. photoAdded: false
  6. };
  7. },
  8. handleChange: function(event) {
  9. this.setState({ text: event.target.value });
  10. },
  11. togglePhoto: function(event) {
  12. this.setState({ photoAdded: !this.state.photoAdded });
  13. },
  14. remainingCharacters: function() {
  15. if (this.state.photoAdded) {
  16. return 140 - 23 - this.state.text.length;
  17. } else {
  18. return 140 - this.state.text.length;
  19. }
  20. },
  21. render: function() {
  22. return (
  23. <div className="well clearfix">
  24. <textarea className="form-control"
  25. onChange={this.handleChange}></textarea>
  26. <br/>
  27. <span>{ this.remainingCharacters() }</span>
  28. <button className="btn btn-primary pull-right"
  29. disabled={this.state.text.length === 0 && !this.state.photoAdded}>Tweet</button>
  30. <button className="btn btn-default pull-right"
  31. onClick={this.togglePhoto}>
  32. {this.state.photoAdded ? "✓ Photo Added" : "Add Photo" }
  33. </button>
  34. </div>
  35. );
  36. }
  37. });
  38. React.render(
  39. <TweetBox />,
  40. document.body
  41. );

  React的套路是监听事件然后改变state,在jsx的模板里,使用这些state展示,而jQuery的套路是监听事件,然后自己去控制DOM展示。React帮你操作DOM,jQuery要自己去操作DOM,前者提供了便利但同时也失去了灵活性,后者增加了灵活性但同时增加了复杂度。

  使用jQuery不少人容易写出面条式的代码,但是写代码的风格我觉得和框架没关系,关键还在于你的编码素质,就像你用了React写class,你就可以说你就是面向对象了?不见得,我在《JS与面向对象》这篇文章提到,写class并不代表你就是面向对象,面向对象是一种思想而不是你代码的组织形式。一旦你离开了React的框架,是不是又要回到面条式代码的风格了?如果是的话那就说明你并没有没有掌握面向对象的思想。不过,React等框架能够方便地组件化,这点是不可否认的。

  还有一个需要注意的是,框架会帮你屏蔽掉很多原生的细节,让你专心于业务逻辑,但往往也让你丧失了原生的能力不管是html还是js,而这才是最重要的功底。例如说对于事件,由于所有的事件都是直接绑在目标元素,然后通过state或者其它第三方的框架进行传递,这样其实就没什么事件的概念了。所以需要警惕使用了框架但是丧失了基本的前端能力,再如ajax分页改变url,或者说单页面路由的实现方式,还有前后退的控制,基本上能够完整回答地比较少。很多人都会用框架做页面,但是不懂JS.

jQuery === 面条式代码?的更多相关文章

  1. 基于jQuery果冻式按钮焦点图切换代码

    基于jQuery果冻式按钮焦点图切换代码.这是一款基于jQuery+CSS3实现的图片切换代码.效果图如下: 在线预览   源码下载 实现的代码. html代码: <div class=&quo ...

  2. jQuery响应式幻灯片插件jquery.glide.js(支持触摸&轻量级)

    找到一款好的幻灯片插件不容易,找到一款功能全并且使用很简单的幻灯片更不容易,今天为大家分享一款全能的幻灯片插件glide.js,也是我现在在使用的一款插件. jquery.glide.js是响应和触摸 ...

  3. jQuery链式操作

    讨论jQuery的文章很多.然而,关于jQuery的链式操作的文章并无多少.好的代码会带来速度的提升.快速渲染和响应意味着更好的用户体验. 下面就来讲讲jQuery的链式操作. 很多时候我们写代码的时 ...

  4. jQuery链式语法演示

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  5. JQUERY链式操作实例分析

    本文实例讲述了jQuery链式操作.分享给大家供大家参考,具体如下: 从过去的实例中,我们知道jQuery语句可以链接在一起,这不仅可以缩短代码长度,而且很多时候可以实现特殊的效果. <scri ...

  6. 基于jquery响应式网站图片无限加载瀑布流布局

    分享一款效果非常酷的jQuery瀑布流布局无限加载图片效果.整个页面采用响应式布局,图片采用jQuery.Lazyload延时加载技术,提升整个页面的加载速度.效果图如下: 在线预览   源码下载 实 ...

  7. 轻量级jQuery语法高亮代码高亮插件jQuery Litelighter。

    <!DOCTYPE html><html><head><meta charset="UTF-8" /><title>jQ ...

  8. 在线运行Javascript,Jquery,HTML,CSS代码

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" http://www.w3.org/TR/xht ...

  9. 18款js和jquery文字特效代码分享

    18款js和jquery文字特效代码分享 jQCloud标签云插件_热门城市文字标签云代码 js 3d标签云特效关键词文字球状标签云代码 原生JS鼠标悬停文字球状放大显示效果代码 原生js文字动画圆形 ...

随机推荐

  1. Jetty的工作原理

    Jetty的工作原理 Jetty 的基本架构 Jetty 目前的是一个比较被看好的 Servlet 引擎,它的架构比较简单,也是一个可扩展性和非常灵活的应用服务器,它有一个基本数据模型,这个数据模型就 ...

  2. LoadRunner性能测试-LoadRunner工具安装

    Loadrunner11安装 1,在网上下载loadrunner11安装包 (百度可以下载安装包) 2,打开安装文件,点击setup.exe进行安装: 3,win10系统可能会出现如下问题: 提示管理 ...

  3. [补档][HNOI 2008]GT考试

    [HNOI 2008]GT考试 题目 阿申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字. 他的不吉利数学A1A2... ...

  4. MySQL基础简介

    MySQL最流行的关系型数据库管理系统 MySQL官网:http://www.mysql.com MySQL是WEB应用方面最好的RDBMS应用软件之一 RDBMS:Relational Databa ...

  5. 【NO.8】jmeter-场景-上传文件-send-a-file

    简要说就3点: POST请求 Request的参数都写在路径内,不写在表单里 上传的文件写在表单里 只要记住以上3点,也就避免了在设计脚本的时候走弯路.下面具体图文并茂地介绍如何使用Jmeter实现上 ...

  6. MATLAB批量读入图片

    %% import pictures, and save into images{img_num} function [images, img_num, vertical_border] = impo ...

  7. python之--------封装

    一.封装: 什么是封装呢?(封装不是单纯意义的隐藏,其实它还是可以查看的) 就是把一些不想让别人看的给隐藏起来了 封装数据:目的是保护隐私 功能封装:目的是隔离复杂度 如果用了私有的,在类的外部,无法 ...

  8. OSX 监听系统网络设置

    由于日常开发的需求,我们需要监听OSX一些系统设置的变化,达到软件程序设置的同步,这时我们可以通过以下函数监听系统设置的改变: #include <SystemConfiguration/Sys ...

  9. AFNetworking源码简析

    AFNetworking基本是苹果开发中网络请求库的标配,它是一个轻量级的网络库,专门针对iOS和OS X的网络应用设计,具有模块化的架构和丰富的APIs接口,功能强大并且使用简单,深受苹果应用开发人 ...

  10. 用jlink在mini2440上烧写uboot

    首先,附上我安装jlink驱动: http://download.csdn.net/detail/zzmno1/3776716#comment 以及我使用的uboot.bin文件下载地址: http: ...