jQuery是06年开发出来的工具库,作为曾经风靡全球十多年的最优秀的js库,其中涉及到的设计理念非常先进。最近在学习时,深感这些造轮子的程序员伟大之处是能将非常基础的代码设计成高深且简便的工具库供人使用,通过jQuery源码的学习,除了对前人的景仰,还学习到更多开放的代码风格,在这里做一些笔记。
选择网页元素
jQuery的主要用法,是通过其创造好的API获取网页元素,并对网页元素做一些操作。
实际上jq通过函数$()来返回一个jQuery对象,这个对象是由jQuery构造出来的,通过选中对应的元素来做一些操作。
写法示例:
$('div')
$('#div')
$('.div')
$('.div span')
那么,我们怎样可以实现这样的代码呢?
window.jQuery = function(selector){
let elements = document.querySelectorAll(selector);
let api ={};
return api
}
window.$ = window.jQuery
你没看错,返回的是另外一个莫名其妙的对象,那么,我只要使用闭包的方式将elements传入api对象的方法中,不就可以实现对elements进行操作了吗?
addClass
在jQuery中,我们使用$('div').addClass('red')来给获取的元素添加class名,那么如何实现源码呢?
window.jQuery = function(selector){
let elements = document.querySelectorAll(selector);
let api ={
addClass(classname){
for(let i=0;i<elements.length;i++){
elements[i].classList.add(classname)
}
return this
}
};
return api
}
window.$ = window.jQuery
上面代码中,由于获取到的elements是伪数组,所以我们要进行遍历,并且给它添加class名
链式操作
上面代码addClass中有一个return this,这就是链式操作的秘密,我们通过addClass函数对获取到的elements进行操作后,如果返回自己,那就等同于一直能够让自己继续操作。
$('.logo').addClass('red').addClass('black').addClass('pink')
attr获取或者设置重载
在jq中,我们可以使用attr来获取或者设置Attribute属性,这是由参数决定的,所以我们可以使用重载来完成
window.jQuery = function(selector){
let elements = document.querySelectorAll(selector);
let api ={
attr(attributename, value) {
let arr = []
for (let i = 0; i < elements.length; i++) {
if (arguments.length === 2) {
elements[i].setAttribute(attributename, value)
} else {
arr.push(elements[i].getAttribute(attributename))
}
}
return arr.length === 0 ? this : arr
}
};
return api
}
window.$ = window.jQuery
find
如果我们想要获取元素的后代,可以使用find()函数
写法:$('div').find('.span').addClass('red')
这个函数如果要简单实现难点在于如果我查找到对应的的子元素,那么如果还要实现链式操作,我需要 返回一个对象
window.jQuery = function(selector){
// let elements = document.querySelectorAll(selector);刚开始的代码
//为了跟下面代码配合所采取的重载,因为jQuery(arr)是一个数组
let elements;
if(typeof selector ==='string'){
elements = document.querySelectorAll(selector)
}else{
elements = selector
}
let api ={
find(selector){
let arr=[]
for(let i=0;i<elements.length;i++){
let arr2=elements[i].querySelectorAll(selector)
arr = arr.concat(Array.from(arr2))
}
// return arr 如果直接return arr肯定没办法实现链式操作
let newApi = jQuery(arr) //再使用一个jQuery构造一个对象
newApi.oldApi =this //把现在的对象挂到新对象的oldApi上
return newApi
}
}
return api
}
window.$ = window.jQuery
end()
上面代码中,我们使用newApi.oldApi =this来保存当前运行的对象,当我们想回到上一个运行对象,再进行操作时,可以使用 end(){return this.oldApi}来返回上一级运行对象
<源码链接>