write less, do more.
jQuery几乎可以说是最流行的前端JavaScript库,最近准备看一下jQuery的源码,学习一下他的编程思路。1.7.2版本的jQuery代码一万多行,短期内必然不可能都理清,所以我只关注了他的核心模块:选择器,DOM操作,事件处理和Ajax等。匆忙中阴差阳错买了第二版的《锋利的jQuery》,回来一看此书好像没怎么讲jQuery的源码,主要还是讲应用于实战,想来我也没系统的学习过jQ,因此就想着先粗略过一遍此书。我非常赞同jQuery的理念:
write less, do more.
一、概述
相对于其它JS库,它的优势也很明显:
- 轻量级,压缩后只有30KB左右;
- 强大的选择器,不仅支持CSS选择器,还封装了jQ特有的高级选择器;
- 可靠的事件处理机制;
- 完善的ajax;
- 出色的兼容性,丰富的插件与文档;
- 链式操作,隐式迭代等机制;
二、jQuery对象
jQuery对象区别于DOM对象,一般来说通过JS选择器document.getElementBy
得到的对象是DOM对象,通过jQ选择器得到的是jQuery对象。需要注意的是:
jQuery对象和DOM对象不能使用对方的方法,比如
$('#id').innerHTML
和document.getElementById('id').html()
的用法是错误的。
两者的相互转换的方法:
- jQuery对象转换为DOM对象:使用[index]和get(index)方法,比如
$('#id')[0]
得到的就是DOM对象;- DOM对象转换为jQuery对象:直接使用
&()
将DOM对象包装起来就可以。
&()
是jQuery的工厂函数,粗略看了一下源码的初始化部分:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17jQuery.fn = jQuery.prototype = {
constructor: jQuery,
init: function( selector, context, rootjQuery ) {
var match, elem, ret, doc;
// Handle $(""), $(null), or $(undefined)
if ( !selector ) {
return this;
}
// Handle $(DOMElement)
if ( selector.nodeType ) {
this.context = this[0] = selector;
this.length = 1;
return this;
}
······
其中处理DOM对象部分的大致意思是:判断元素的nodeType(1表示元素节点,2表示属性,3表示文字节点,8表示注释等),如果是某一种节点则返回一个装着DOM本身的数组,当然这个数组挂载了众多的jQuery方法。
上面代码的第一行说明了返回的jQuery对象继承jQ方法是通过修改原型链实现的,当使用某个方法时,如果当前对象没有找到则沿着原型链查找,所有子类共享同样的方法和数据。
三、jQuery选择器
jQuery选择器支持CSS选择器的语法,同时也遵循CSS选择器的优先级机制:ID选择器权值100,类为10,标签为1,权值求和越高优先级也越高,具体使用方法不再赘述。jQuery选择器的一个优势就是:
操作不存在的元素时不会报错。
因此判断是否选择了元素应该判断长度是否大于0。jQuery选择器大致分为以下几类:
- 基本选择器:ID,类,标签,集合选择器等;
- 层次选择器:中间有连字符的,比如后代,兄弟选择器等;
- 基本过滤选择器:以冒号开始,比如:first,:not(selector)等;
- 内容过滤选择器::contains(text)表示含有text文本内容的元素,:has表示含有selector选择器匹配元素的元素;
- 可见性过滤选择器::hidden表示选择所有不可见元素,:visible表示选择所有可见元素;
- 属性过滤选择器:以[]包裹,格式为:
[属性 判别符 值]
,多个[]串联表示与关系; - 子元素过滤器::nth-child,:first-child,:last-child等;
表单属性过滤器:针对表单元素进行过滤::enabled,:disabled,:checked,:selected;
表单选择器:直接选取表单元素,比如:input,:button,:password等;
四、DOM操作
先说一下DOM的定义:
DOM(Document Object Model):文档对象模型,它是一种与浏览器、平台、语言无关的接口,使用该接口可轻松访问页面中所有的标准组件。
DOM操作分三类:
- DOM core:核心操作,比如
getElementBy
和getAttribute
等; - HTML-DOM:专门针对html文档的操作,比如
document.forms
,document.src
,通常会比更简短; - CSS-DOM:针对CSS的操作,主要用于获取或设置style对象的属性,如
elem.style.color=#ccc
;
jQuery中的DOM操作
1. 查找节点
查找属性节点直接通过选择器就行,查找属性节点通过attr方法:$('#id').attr(title)
表示获取title属性节点的值。
2. 创建节点
通过给$()
传入包含html标签的字符串实现,标签中可以包含任意的文本或者属性节点。
3. 插入节点
append
/appendTo
:插入到指定元素内部的最后面;prepend
/prependTo
:将元素插入到指定元素内部的最前面;after
/insertAfter
:插入到指定元素外部的紧接着的后面;before
/insertBefore
:插入到指定元素外部的紧接着的前面;
4. 删除节点
使用remove()
方法删除元素及其后代所有节点,使用empty()
可以清空元素内部的节点,元素的标签依然会存在。
5. 复制节点
使用clone()
方法可以复制一个节点及其后代节点,传入形参true可以复制绑定在元素上的事件。
6. 替换节点
使用replaceWith()
进行元素替换,替换后事件自动失效;
7. 包裹节点
wrap()
方法可以将匹配元素分别用传入的标签包裹起来:$('id').wrap('<b></b>')
,而wrapAll()
方法将匹配的元素一起用指定的标签包裹。最后wrapInner()
方法是在匹配元素内部对所有后代进行包裹。
jQuery中的属性操作
attr()
用于获取元素属性,removeAttr()
用于删除属性。addClass()
和removeClass()
分别用于添加和删除类名,toggleClass()
用于切换样式,hasClass用于判断是否含有某个样式。html()
和text()
用于获取html和文本值,前一个方法获取的值包括html标签,后者只包含文本。val()
用于获取或设置文本框,多选框,单选框的值。
DOM树遍历
DOM树的遍历是前端常用的操作之一,使用jQuery能够大大简化代码,相比原生JS更加高效强大。
children()
:获取匹配元素的子元素集合,只包含子元素,不包含其它后代元素。next()
和prev()
:分别获取匹配元素后面和前面紧邻的同辈元素。siblings()
:获取匹配元素前后所有的同辈元素。closest()
:获取最近的匹配元素,从当前节点开始逐层往上查找。parent()
用于获取每个匹配元素的父级元素,parents()
返回多个父节点。
CSS-DOM操作
原生JS中的style对象可用于获取CSS属性,其不足在于不能获取由外部CSS设置的样式,比如一个节点没有直接在行内设置width,而是在CSS样式表中设置了width,那么通过style.width的方式是无法获得宽度的(依然可以用于设置宽度)。在jQuery中无论属性是通过外部CSS导入还是直接拼接在元素里,css()
方法都可以获取到属性值。使用css()
设置多个属性时,需传入一个对象,里面是需要设置的属性名和值。height()
和width()
方法用于获取元素实际的大小,默认单位是px。offset()
方法获取元素在当前窗口的相对偏移。包含top和left两个属性。position()
方法用于获取元素相对于最近的一个position被设置为relative或者absolute的祖父节点的相对偏移,同样包含top和left两个属性。scrollTop()
和scrollLeft()
方法用于获取元素的滚动条距顶端和左侧的距离。
五、jQuery中的事件
jQuery中最经典的要数$(document).ready()
了,这个方法绑定的函数会在DOM树加载完成(图片等可能还未加载完)的时候执行,观察jQuery源码,这个应该是通过先把函数push到一个数组,等到document.readyState === "complete"
时再去执行数组里的函数。jQuery中使用bind
和typename=
方式绑定事件的效果是一样的,用法不再详述,值得注意的是jQuery事件不支持事件捕获。接下来重点说两个方面:自定义事件和on()
方法。
自定义事件
jQuery中使用自定义的方法自然并且优雅,方法和绑定一般事件一样,触发时使用trigger函数,并且支持传递数据:1
2
3
4$('#id').bind('uesrEvent',function(data){
//do something
});
$('#id').trigger('uesrEvent','data'); //触发事件
on方法
on()
方法可以用于绑定一般事件,但是更重要的用处是进行“事件委托”。在为大量DOM元素绑定相同事件时,使用事件委托可以大大提高性能,jQuery中on方法的调用格式如下:1
2
3
4
5
6
7
8
9
10$(element).on(event //待绑定的事件,支持自定义事件,element是被委托的元素
[,selector] //检查事件来源时比较的对象
[,data] //传递的参数
,handler); //绑定的函数
/*表示当document触发了click事件,
检查这个事件是否由后代元素中的标签a所触发,
如果是,则执行handler函数*/
$(document).on("click","a",handler);
$(element).on("event",handler); //相当于$(element).bind("event",handler)
六、jQuery中的Ajax
jQuery封装的Ajax有三层:最底层的$.ajax()
提供丰富的选项。第二层的load()
,$.get()
和$.post
用于载入一个url的内容,与服务器交换数据,加载js脚本等。第三层的$.getJSON()
和getScript()
用于加载指定类型的文件。
load()
1 | load(url //请求地址,地址中可以传入以空格隔开的filter用于选取返回的html中指定的内容 |
get()和post()
get和post都是jQuery的全局函数,load是应用在jQuery对象上的。1
2
3
4
5get(url //请求地址
[,data] //发送至服务器的数据,追加在url中
[,callback] //执行的回调函数,成功时执行,只有两个参数:返回的数据和状态
[,type] //指定服务端返回的格式
);
1 | post(url //请求地址,地址中可以传入以空格隔开的filter用于选取返回的html中指定的内容 |
$ajax()
该方法所需的参数选项以键值对的方式保存在对象中,详见。