自从React/Vue等框架流行以后,jQuery被打上了面条式代码的标签,甚至成了“过街老鼠”,好像谁还在用jQuery,谁就还活在旧时代,不少人都争先恐后地拥抱新框架,各大博客网站有很大一部分的博客都在介绍新的框架,争当时代的“弄潮儿”。新框架带来的新的理念,新的开发方式不能否认带来了生产效率,可是jQuery等就应该被打上“旧时代”面条式代码的标签么?javascript
咱们从一篇文章提及:《React.js 的介绍 - 针对了解 jQuery 的工程师(译)》,英文原文是这个《React.js Introduction For People Who Know Just Enough jQuery To Get By》, 这篇文章我很久前就看过,如今再把它翻出来,里面对比了下jQuery和React分别实现一个发推的功能,做者用jQuery写着写着代码就乱套了,而用React无论需求多复杂,代码条理依旧很清晰。css
咱们一步步按照原文做者的思路来拆解。html
以下图所示,当输入框没有内容时,发推按钮置灰不可点,有内容点才能点。前端
做者写的代码是这样的:java
// 初始化状态
$("button").prop("disabled", true);
// 文本框的值发生变化时
$("textarea").on("input", function() {
// 只要超过一个字符,就
if ($(this).val().length > 0) {
// 按钮能够点击
$("button").prop("disabled", false);
} else {
//不然,按钮不能点击
$("button").prop("disabled", true);
}
});复制代码
这个代码自己写得很累赘,首先,既然一开始那个button是disabled的,那就直接在html上写个disabled属性就好了:react
<form class="tweet-box"> <textarea name="textMsg"></textarea> <input disabled type="submit" name="tweet" value="Tweet"> </form>复制代码
第二个要控制按钮的状态,其实核心只要一行代码就好了,不须要写那么长:jquery
let form = $(".tweet-box")[0];
$(form.textMsg).on("input", function() {
form.tweet.disabled = this.value.length <= 0;
}).trigger("input");复制代码
这个代码应该够简洁了吧,并且代码在jQuery和原生之间来回切换,游刃有余。ajax
以下图所示:segmentfault
这个也好实现:框架
let form = $(".tweet-box")[0],
$leftWordCount = $("#left-word-count");
$(form.textMsg).on("input", function() {
// 已有字数
let wordsCount = this.value.length;
$leftWordCount.text(140 - wordsCount);
form.tweet.disabled = wordsCount <= 0;
});复制代码
以下图所示,左下角多了一个选择照片的按钮:
若是用户选择了照片,那么可输入字数将会减小23个字符,而且Add Photo文案要变成Photo Added。咱们先来看下做者是怎么实现的,以下代码:
if ($(this).hasClass("is-on")) {
$(this)
.removeClass("is-on")
.text("Add Photo");
$("span").text(140 - $("textarea").val().length);
} else {
$(this)
.addClass("is-on")
.text("✓ Photo Added");
$("span").text(140 - 23 - $("textarea").val().length);
}复制代码
若是代码像做者这样写的话确实是比较乱,并且比较面条式。可是咱们能够优雅地实现。首先,选择照片通常会写一个input[type=file]的隐藏输入框盖在上传图标下面:
<div class="upload-container"> <img src="upload-icon.png" alt> <span id="add-photo">Add Photo</span> <input type="file" name="photoUpload"> </div>复制代码
而后监听它的change事件,在change事件里面给form套一个类:
$(form.photoUpload).on("change", function() {
// 若是选择了照片则添加一个photo-added的类
this.value.length ? $(form).addClass("photo-added")
// 不然去掉
: $(form).removeClass("photo-added");
});复制代码
而后就能够来实现文案改变的需求了,把上面#add-photo的span标签添加两个data属性,分别是照片添加和未添加的文案,以下代码所示:
<span id="add-photo" data-added-text="Photo Added" data-notadded-text="Add Photo"></span>复制代码
经过form的类结合before/after伪类控制html上的文案,以下代码所示:
#add-photo:before {
content: attr(data-empty-text);
}
form.photo-added #add-photo:before {
content: attr("data-added-text);
}复制代码
这样就能够了,咱们算是用了一个比较优雅的方式实现了一个文案变化的功能,其中CSS的attr能够兼容到IE9,而且这里html/css/js相配合,共同完成这个变化的功能,这应该也挺好玩的。
剩下一个要减掉23字符的需求,只须要在减掉的时候判断一下:
$(form.textMsg).on("input", function() {
// 已有字数
let wordsCount = this.value.length;
form.tweet.disabled = wordsCount <= 0;
$leftWordCount.text(140 - wordsCount -
//若是已经添加了图片再减掉23个字符
($(form).hasClass("photo-added") ? 23 : 0));
});复制代码
而后在选择图片以后trigger一下,让文字发生变化,以下代码倒数第二行:
/* * @trigger 会触发文字输入框的input事件以更新剩余字数 */
$(form.photoUpload).on("change", function() {
// 若是选择了照片则添加一个photo-added的类
this.value.length ? $(form).addClass("photo-added") :
// 不然去掉
$(form).removeClass("photo-added");
$(form.textMsg).trigger("input");
});复制代码
这里又使用了事件的机制,用reac应该基本上都是用状态state控制了。
再来看最后一个功能。
上面是只要没有文字,那么发推按钮不可点,如今要求有图片就可点。这个也好办,由于若是有图片的话,form已经有了一个类,因此只要再加一个判断就能够了:
$(form.textMsg).on("input", function() {
// 已有字数
let wordsCount = this.value.length;
form.tweet.disabled = wordsCount <= 0
//disabled再添加一个与判断
&& !$(form).hasClass("photo-added");
$leftWordCount.text(140 - wordsCount -
//若是已经添加了图片再减掉23个字符
($(form).hasClass("photo-added") ? 23 : 0));
});复制代码
最后看一下,汇总的JS代码,加上空行和注释总共只有23行:
let form = $(".tweet-box")[0],
$leftWordCount = $("#left-word-count");
$(form.textMsg).on("input", function() {
// 已有字数
let wordsCount = this.value.length;
form.tweet.disabled = wordsCount <= 0
//disabled再添加一个与判断
&& !$(form).hasClass("photo-added");
$leftWordCount.text(140 - wordsCount -
//若是已经添加了图片再减掉23个字符
($(form).hasClass("photo-added") ? 23 : 0));
});
/* * @trigger 会触发文字输入框的input事件以更新剩余字数 */
$(form.photoUpload).on("change", function() {
// 若是选择了照片则添加一个photo-added的类
this.value.length ? $(form).addClass("photo-added") :
// 不然去掉
$(form).removeClass("photo-added");
$(form.textMsg).trigger("input");
});复制代码
html大概有10行,还有6行核心CSS,不过这两个比较易读。再来看一下React的完整版本,做者的实现:
var TweetBox = React.createClass({
getInitialState: function() {
return {
text: "",
photoAdded: false
};
},
handleChange: function(event) {
this.setState({ text: event.target.value });
},
togglePhoto: function(event) {
this.setState({ photoAdded: !this.state.photoAdded });
},
remainingCharacters: function() {
if (this.state.photoAdded) {
return 140 - 23 - this.state.text.length;
} else {
return 140 - this.state.text.length;
}
},
render: function() {
return (
<div className="well clearfix"> <textarea className="form-control" onChange={this.handleChange}></textarea> <br/> <span>{ this.remainingCharacters() }</span> <button className="btn btn-primary pull-right" disabled={this.state.text.length === 0 && !this.state.photoAdded}>Tweet</button> <button className="btn btn-default pull-right" onClick={this.togglePhoto}> {this.state.photoAdded ? "✓ Photo Added" : "Add Photo" } </button> </div>
);
}
});
React.render(
<TweetBox />, document.body );复制代码
React的套路是监听事件而后改变state,在jsx的模板里,使用这些state展现,而jQuery的套路是监听事件,而后本身去控制DOM展现。React帮你操做DOM,jQuery要本身去操做DOM,前者提供了便利但同时也失去了灵活性,后者增长了灵活性但同时增长了复杂度。
使用jQuery很多人容易写出面条式的代码,可是写代码的风格我以为和框架不要紧,关键还在于你的编码素质,就像你用了React写class,你就能够说你就是面向对象了?不见得,我在《JS与面向对象》这篇文章提到,写class并不表明你就是面向对象,面向对象是一种思想而不是你代码的组织形式。一旦你离开了React的框架,是否是又要回到面条式代码的风格了?若是是的话那就说明你并无没有掌握面向对象的思想。不过,React等框架可以方便地组件化,这点是不能否认的。
还有一个须要注意的是,框架会帮你屏蔽掉不少原生的细节,让你专心于业务逻辑,但每每也让你丧失了原生的能力不论是html仍是js,而这才是最重要的功底。例如说对于事件,因为全部的事件都是直接绑在目标元素,而后经过state或者其它第三方的框架进行传递,这样其实就没什么事件的概念了。因此须要警戒使用了框架可是丧失了基本的前端能力,再如ajax分页改变url,或者说单页面路由的实现方式,还有先后退的控制,基本上可以完整回答地比较少。不少人都会用框架作页面,可是不懂JS.