前情提要: 2018 年 7 月 26 日,Github 前端团队的 Mislav Marohnić 在 Twitter 发布了一则消息,表明在 GitHub 网站重构过程中放弃了 jQuery,没有再次使用其他任何框架去代替它,而是使用了原生的 JS,这标志着 jQuery 一个时代的结束
好,那么问题来了,我们还有必要学 jQuery 嘛?
当然有必要(废话,要不怎么会有这篇文章???),可以领会一下 jQuery 的封装思想,以后在封装代码的时候可以学着点
jQuery
先看看阮一峰怎么说, jQuery 设计思想
库实际上是特定种类的 api
封装函数
写代码
<li id="item1">选项1</li> |
然后对以上代码进行封装
// 得到该节点的兄弟姐妹 |
再封装一个
var classes = ['a', 'b', 'c'] |
变
var classes = {'a': true, 'b': false, 'c': true} |
封装一下
fucntion addClass(node, classes) { |
使用就是如下addClass(item3, {a: true, b:false, c:true})
命名空间 & Node.prototype
代码优化的原则,如果存在类似的代码,就有优化的可能
就比如像如下
fucntion addClass(node, classes) { |
然后声明变量, 命名空间就是区分库的名字,以下声明的 ffdom
就是其命名空间
window.ffdom = {} |
弄个缩写 aliaswindow.$ = jQuery
最终优化的代码为window.ffdom = {} /*yui*/
ffdom.getSiblings = function (node) { /* API */
var allChildren = node.parentNode.children
var array = {
length: 0
}
for (let i = 0; i < allChildren.length; i++) {
if (allChildren[i] !== node) {
array[array.length] = allChildren[i]
array.length += 1
}
}
return array
}
ffdom.addClass = function (node, classes) {
classes.forEach( (value) => node.classList.add(value) )
}
然后使用就是$.getSiblings(item3)
$.addClass(item3, ['a','b','c'])
那么如何将 ffdom.addClass(item3, ['a', 'b', 'c'])
转化成 item3.addClass(['a', 'b', 'c'])
来使用呢
尝试在 Node
原型链中加入 getSiblings
函数Node.prototype.getSiblings = function () {
return 1
}
console.log(item3.getSiblings()) // 1
console.dir(item3)
可以在控制台看到在 Node
原型中出现了 getSiblings
函数,并且控制台打印出来的数为 1,通过这样的方式我们可以直接在 Node
原型中加函数,然后所有继承自 Node
的元素都可以调用到这个方法
Node.prototype.getSiblings = function() { |
this 是个啥 & Node2
首先我们记得是如何调用函数的
f.call(asThis, input1, input2) |
其中 asThis
会被当做 this, [input1, input2] 会被当做 arguments
以后还是尽量少使用类似 f(input1, input2)
吧
实际上 this 就是 call 的第一个参数
往 Node
里面添加函数的时候容易导致一个问题, 就是函数有可能被覆盖掉,那么有什么方法可以避免这个问题呢?
思路是再写一个 “Node2” ,在这个 “Node2” 中去调用原来的 Node,代码如下所示
window.Node2 = function(node) { |
开始认识 jQuery
好了,将 Node2 变成 jQuery ,就是如下
window.jQuery = function(node) { |
所以 jQuery 的初步印象就是这样,给一个旧的对象,然后返回一个新的对象以及这个新对象的 api,但实际上这个新的 api 还是调用了旧的 api
所以 JQuery 实际上是一个构造函数,这个构造函数接受一个参数,这个参数可能是一个节点,这个构造函数被调用后返回一个对象,通过操作这个对象里的方法去操作节点
但是 JQuery 会更加聪明,假如传的是一个字符串(一个css选择器),它在代码里会做类型检查
window.jQuery = function(nodeOrSelector) { |
上面也同时使用到了闭包,因为 addClass
这个函数,里面使用到了 node
变量 , 而这个 node 是在该函数的外面进行声明的,我们对这个变量 node
和 这个匿名函数统称为 闭包,闭包的好处在于,它维持住了 node
这个变量,只要有 addClass
被调用的场合,它就不会消失,并且外面的代码也不能直接访问到 node
这个变量,因为作用域在 function(nodeOrSelector)
里面
操作多节点
那么如何操作多个节点呢?
window.jQuery = function(nodeOrSelector) { |
jQuery 使用举例
中文文档参见 cndevdocs
html 代码<ul>
<li>选项1</li>
<li>选项2</li>
<li>选项3</li>
<li>选项4</li>
<li>选项5</li>
</ul>
<button id="x">X</button>
css 代码.red {
color: red;
}
js 代码var nodes = jQuery('ul > li')
x.onclick = function() {
nodes.toggleClass('red') // toggle 开关 切换
}
或者还可以链式操作
html 代码<ul>
<li class="red">选项1</li>
<li class="red">选项2</li>
<li class="red">选项3</li>
<li class="red">选项4</li>
<li class="red">选项5</li>
</ul>
<button id="x">X</button>
css 代码.red {
color: red;
}
.green {
color: green;
}
js 代码var nodes = jQuery('ul > li')
x.onclick = function() {
nodes.removeClass('red').addClass('green')
}
还有个 addClass
html 代码<ul>
<li>选项1</li>
<li>选项2</li>
<li>选项3</li>
<li>选项4</li>
<li>选项5</li>
</ul>
<button id="x">X</button>
css 代码.red {
color: red;
}
.blue {
color: blue;
}
.green {
color: green;
}
.yellow {
color: yellow;
}
.black {
color: black;
}
js 代码var nodes = jQuery('ul > li')
var classes = ['red', 'blue', 'green', 'yellow', 'black']
x.onclick = function() {
nodes.addClass(function(index, currentClass) {
return classes[index]
})
}
总结
- jQuery 兼容性方面做的很好, 1.7 版本兼容到 IE6,但是现在 3 版本已经不做 IE 的兼容了
- jQuery 还有动画 AJAX 等模块,不止 DOM 操作
- jQuery 功能更丰富
- jQuery 使用了 prototype 以及 new
小技巧:
如果用的是 jQuery,声明变量最好这样写var $nodes = $('ul>li')
这样可以提醒自己用的是 jQuery 的 api
以上为大概对 jQuery 的初步理解