jQuery API 学习小扎(上)
作为一个专业的前端开发,你真的会用 jQuery 吗?jQuery 的精妙,随着我对 JavaScript 的理解的加深而愈加感到惊讶
其实,如果我们不需要进行对 DOM 的操作兼容(主要针对 IE),那么大抵可以完全抛弃 jQuery,毕竟 ES5 和 DOM-Lv2 已经提供了很多 jQuery 常用的功能了,既然使用 jQuery 是为了开发效率和兼容性考量,那么我是很推荐尽量使用 jQuery 提供的大部分功能,毕竟这样对代码阅读者和书写者都是很舒服的事情,使用
$.each()代替了常规的for循环,使用$.isEmptyObject(object)来判断空对象,等等很多人觉得使用 jQuery 不够高端,甚至觉得它会带来性能问题,但其实我认为,对于快速迭代的考虑,代码的可读性和兼容性优先级要远高于那点可怜的性能加成(事实上,自己造的轮子真不一定比 jQuery 性能好,简单的例子,jQuery 通常会考虑缓存 DOM,同时不会忘记卸载过期事件)
本文档基于 jQuery API 中文文档 总结
关于jQuery的最佳实践
可参考 阮一峰 的整理 jQuery最佳实践,关键点如下:
- 使用最新版本的 jQuery
- 用对选择器(尽量用 ID)
- 理解子元素和父元素的关系
- 不要过度使用 jQuery
- 做好缓存
- 使用链式写法
- 事件的委托处理
- 少改动 DOM 结构
- 正确处理循环
- 尽量少生成 jQuery 对象
- 选择作用域链最短的方法
- 使用 Pub / Sub 模式管理事件(观察者模式)
选择器
jQuery 实现的选择器方法很多已经大放异彩,堪称业界典范,同时这个抽出来单独作为一个标准——Sizzle 选择器引擎
避免使用的选择器
以下的选择器均有或多或少的性能问题,主要原因是无法充分利用原生 DOM 提供的
querySelectorAll()方法
$('*')$(':eq')$(':gt')$(':lt')$(':not')$(':has')$(':file')(建议替换成$('selector[type = "file"]'))$(':checkbox')(建议替换成$('selector[type = "checkbox"]'))$(':image')(建议替换成$('selector[type = "image"]' ))$(':password')(建议替换成$('selector[type = "password"]'))$(':radio')(建议替换成$('selector[type = 'radio']'))$(':reset')(建议替换成$('selector[type = 'reset']'))$('[attribute != "value"]')(建议替换成$('class'))
尽量先使用纯CSS选择器,再使用 .filter('selector') 代替的选择器
$(':hidden')和$(':visible')visibility: hidden或opacity: 0在 jQuery 中被认为是可见的,因为他们仍然占据布局空间
相对地,不可见主要根据以下四点判断(jQuery 3.0 对该标准有所修改)- 他们的CSS
display值是none - 他们是
type="hidden"的表单元素 - 它们的宽度和高度都显式设置为
0 - 一个祖先元素是隐藏的,因此该元素是不会在页面上显示
- 他们的CSS
$(':animated')$(':even')和$(':odd')(注意与$(':nth-child(even)')及$(':nth-child(odd)')的区别)$(':first')和$(':last')$(':header')$(':empty')和$(':parent')涉及到的子元素包括文本节点- 表单元素:
$(':button'),$(':input'),$(':selected'),$(':submit'),$(':text')
比较特殊的选择器
$(':target')$(':lang')$(':root')(建议换用$('html')替换,提高可读性)$(':contains(text)')查找的一个文本字符串,区分大小写$(':nth-child(n)')索引从1开始$(':focus')如果正在寻找当前的焦点元素,可使用$(document.activeElement)检索,而不必查找整个 DOM 树$(':disabled')检查元素的disabled属性的布尔值,$(['type = "disabled"]')检查是否存在的disabled属性
CSS和属性
用法区别
.prop()方法 方法返回property的布尔值,.attr()方法返回attributes的字面量值,区别使用.prop(),.attr(),.val(),.css()等方法只获取或设置第一个匹配元素的属性值 。如果元素上没有该属性,或者如果没有匹配的元素。那么该方法会返回undefined值.css('height')和.height()之间的区别是后者返回一个没有单位的数值(例如,400),前者是返回带有完整单位的字符串(例如,400px)尺寸计算方法间的区别






计算
window和document的高度1234// 获取浏览器视口宽高 viewport$(window).height();// 获取文档宽高 document$(document).height();.offset()方法检索一个元素相对于文档document的当前位置。和.position()的差别是:.position()是相对于相对于父级元素的位移.offsetParent()取得离指定元素最近的含有定位信息的祖先元素
注意事项
当设置样式名
("class")属性时,必须使用引号,因为class是 JavaScript 标识符,为保持风格统一和安全,建议 API 调用传入类似对象的属性名均使用引号,如下1234$('body').attr({'alt': 'Beijing Brush Seller','class': 'photo'});.prop(),.attr()Properties 属性一般影响 DOM 元素的状态并不会改变序列化的 HTML attribute 属性。例如,
input元素的value属性,input和button元素的disabled属性,以及checkbox的checked属性。应该使用.prop()方法设置disabled和checked属性,而不是使用.attr()方法.val()方法应该用于存取value值。还要注意的是.removeProp()方法不应该被用来设置这些属性为false。一旦原生的属性被移除,就无法再被添加在 IE8 及以下版本,不要使用
.prop()对非基本类型(number、string或boolean)的属性赋值,为了安全请使用.data()方法尺寸相关的 API 返回的数字, 包括的
.height(), 在某些情况下可能带有小数。你的代码不应该假定它是一个整数。 另外,当页面被用户缩放时,返回的尺寸可能是不正确的;浏览器没有一个公开的 API 来检测这种情况。当元素或其父元素被隐藏时,
.height()得到的值不能保证准确。要得到准确的值,你应该确保该元素在使用.height()前可见。jQuery 将尝试临时显示,然后再隐藏元素来测量元素尺寸,但这是不可靠的,(即使得到准确的值)也会显著影响页面的性能。这总临时显示然后再隐藏的测量功能,可能在 jQuery 未来的版本中删除。
实用技巧
通过函数回调的方法动态获取 / 修改属性等
12345678// 适用于.prop(), .attr(), .val(), .addClass(), .removeClass(), .css(), toggleClass()$('div').attr('title', function (index, val) {return index + val; // index 为索引,val为属性title的值});//实际应用$('img').attr('src', function () {return '/resources/' + this.title; // title为图片名,动态修改其相对路径});.val()方法1234567// 通过 .val() 方法从 textarea 元素中取得的值是不含有回车(\r)字符的。// 但是如果该值是通过 XHR 传递给服务器的,回车(\r)字符会被保留(或者是被浏览器添加的,但是在原始数据中并不包含回车(\r))。$.valHooks.textarea = { // 原始数据中保留回车(\r)字符get: function (elem) {return elem.value.replace( /\r?\n/g, "\r\n" );}};
特殊
$.cssHooks直接向 jQuery 中添加钩子,用于覆盖设置或获取特定 CSS 属性时的方法,目的是为了标准化 *CSS 属性名或创建自定义属性.toggleClass()可以传入 Boolean 值或回调函数来灵活调整切换
避免使用
$.data( element, key, value )存储任意数据到指定的元素,返回设置的值。 允许我们在DOM元素上绑定任意类型的数据,避免了循环引用的内存泄漏风险, 这是一个底层的方法,你应该用.data()代替
操作
用法区别
.prepend('将要插入的内容')和.prependTo('位置')均为 内部 插入后面,.append('将要插入的内容')和.appendTo('位置')均为 内部 插入前面.after('将要插入的内容')和.insertAfter('位置')均为 外部 插入后面,.before('将要插入的内容')和.insertBefore('位置')均为 外部 插入前面.empty()移除节点内容(不含节点)并解除数据 / 事件关联,.remove()移除节点内容(含节点)并解除数据 / 事件关联,.detach()移除节点内容(含节点)但不解除数据 / 事件关联(再插回来还能用).unwrap()删除元素的父级元素。和.wrap()的相反.replaceAll('位置')和.replaceWith('内容')功能类似,目标和源相反,用来替换的元素从老地方移到新位置,而不是复制,并且会删除与节点相关联的所有数据和事件处理程序
特殊
.clone([withDataAndEvents] [, deepWithDataAndEvents])深度复制所有匹配的元素集合,包括所有匹配元素、匹配元素的下级元素、文字节点
注意事项
使用
.html()时元素中的任何内容会完全被新的内容取代。新的内容替换前,jQuery 从子元素删除其他结构,如数据和事件处理程序(这样可以防止内存溢出)在 IE 中(包括 IE9),设置 HTML 元素的文本内容可能会破坏其子节点的文本节点,结果导致子节点的文本节点从文档中被删除。如果你想保留这些 DOM 元素的引用,需要他们将保持不变,请使用
.empty()来代替.html(string)以便从文档中删除元素之前的元素被分配到新的字符串要设置一个
<script>元素的内容, 其不包含 HTML, 使用.text()方法而不是.html(),.text()方法不能使用在input元素或scripts元素上。input或textarea需要使用.val()方法获取或设置文本值。得到scripts元素的值,使用.html()方法
遍历
用法区别
.filter(function(index))通过函数来进行高级筛选123$('li').filter(function (index) { //this是当前DOM元素,index为索引return $('strong', this).length == 1;}).css('background-color', 'red');.map(callback(index, domElement))方法特别适用于获取或设置元素集合中的值.slice(start [, end ])根据指定的下标范围,过滤匹配的元素集合,并生成一个新的 jQuery 对象add()添加新 jQuery 对象到堆栈,而addback()添加堆栈中元素集合到当前集合.contents()和.children()检索直接子元素,.find()检索后代元素,其中.contents()包括文本节点和注释节点,以及 jQuery 对象中产生的 HTML 元素.parent()匹配直接父元素,.parents()匹配祖先元素(不包括自己,可能返回元素数组),.parentsUntil()查找并返回遇到跟参数匹配的元素(不包括)前的所有祖先元素,.closest()匹配祖先元素(包括自己,只返回最近一个).next()、.nextAll()与.nextUntil()和.prev()、.prevAll()与.prevUntil()两组用法类似$("html").parent()方法返回一个包含 document 的集合,而$("html").parents()返回一个空集合
其他
.each(function(index, Element))方法用来让 DOM 循环结构更简单更不易出错。123456$('li').each(function (index) {console.log(index + ': ' + $(this).text()); // this 总是指向对应的 DOM 元素,使用 $(this) 获得的是 jQuery 对象if (index === 3) {return false; // 使用return提前结束each()}});end()可用于链式写法 终止在当前链的最新过滤操作,并返回匹配的元素的以前状态1234$('ul.first').find('.foo').css('background-color', 'red').end().find('.bar') // 返回到 $('ul.first') 的栈.css('background-color', 'green')
效果
基础动画
- 所有jQuery效果都能通过设置
jQuery.fx.off = true全局地关闭,效果等同于持续时间设置为0 - 元素的
display原本属性值保存在 jQuery 的数据缓存,这样使用切换显示的方法时,将恢复其原本display值 - 可以传入一个回调在对应动画完成后运行,比如在 弹窗中,淡出后删除其对应 DOM 结构
.fadeTo()方法调整匹配元素的透明度
自定义动画
- 建议避免使用复杂的 jQuery 动画,使用 CSS3 动画以在高级浏览器中获得更好性能与表现
事件
jQuery 的事件绑定子系统为每一个事件处理函数分配一个唯一的 ID 用于对其进行跟踪,这样的话,当需要解除绑定特定的事件处理时,系统就知道该解除绑定哪个事件处理函数
常见事件类型及用法
$(document).ready(handler)与$(handler)等价,前者更语义化123jQuery(document).ready(function ($) {// 当引入其他类库时,在此可正常使用 $});.ready()方法通常和<body onload="handler">属性是不兼容的。如果load必须使用,要么不使用.ready(),要么使用 jQuery 的.load()方法向window或一些指定的元素(例如,图片)绑定load事件- 为代码统一及便于记忆,建议事件绑定均使用通用方法而不是速写方式,首选方法
.on()、.off()和.trigger():- 浏览器事件:
.resize()与.scroll() - 表单事件:
.blur(),.change(),.focus(),.select(),.submit() - 键盘事件:
.keydown(),.keypress(),.keyup() - 鼠标事件:
.click(),.contextmenu(),.dbclick(),.focusin(),.foucsout(),.hover(),.mouseenter(),.mouseleave(),.mousedown(),.mouseup(),.mousemove(),mouseout()
- 浏览器事件:
resize事件处理中的代码,不应该依赖于事件被调用的次数。由于不同浏览器对该事件实现的方式不同,该事件被调用的时机也不同一个元素的值改变的时候将触发
change事件。此事件仅限用于<input>,<textarea>和<select>元素注意:使用 JavaScript 改变输入元素的值,例如使用
.val(),将不会触发该事件。在一个元素中进行文本选择时,
select事件就会被触发。此事件只用在<input type="text">和<textarea>按下并按住这个键(不松开)的时,
keydown事件只触发一次,但是keypress会在每个字符插入的时候都会触发。组合键(如Shift)会触发keydown事件,但不会触发keypress事件。值得注意的是
keydown和keyup提供一个代码,表示哪一个键被按下,而keypress表示被输入哪个字符。例如,按下了小写的
a,在keydown和keyup中,对应该键的代码是65,但是对于keypress而言,接收到的代码是97。如果是大写A的话,则所有的相关事件接收到的代码都是65。由于这个区别,若想捕获敲击了哪个特殊键的话,例如方向键,使用
.keydown()或.keyup()更好。如果要捕获实际输入文本,.keypress()可能是一个更好的选择。focusin(或focusout)事件会在元素(或者其内部的任何元素)获得焦点时触发。这跟focus(或blur)事件的显著区别在于,它可以在父元素上检测子元素获得焦点的情况(换而言之,它支持事件冒泡).hover()方法同时绑定mouseenter和mouseleave事件$(selector).hover(fnIn, fnOut)是 $(selector).mouseenter(fnIn).mouseleave(fnOut)的简写mouseleave与mouseout、mouseenter与mouseover之间的不同之处是事件的冒泡的方式, 一般用前者mouseleave事件是IE专有的, 由于该事件在平时很有用, jQuery 模拟了这一事件,使它可用于所有浏览器
事件绑定
- 使用
.on()方法带代替.delegate()(多元素绑定)和.bind()(单元素绑定)方法将事件处理程序绑定到document one()方法绑定一次性事件, 等价于.on()触发事件后马上off().trigger()模拟事件的触发,具备合成的 event 对象。如不希望触发默认事件或冒泡,使用.triggerHandler()
事件对象
event.currentTarget总是等于该函数的thisevent.data作为一个数据对象传递给一个事件event.preventDefault()阻止默认事件行为event.isDefaultPrevented()、event.isImmediatePropagationStopped()和event.isPropagationStopped()均为判断对应方法是否调用过,返回布尔值event.pageX和event.pageY为鼠标相对于document的左边缘的位置(左/右)event.stopImmediatePropagation()阻止 剩余 的事件处理函数执行并且防止事件冒泡到 DOM 树; 而event.stopPropagation()不会阻止同一元素上的其它事件,同样防止事件冒泡到 DOM 树上(不触发任何前辈元素上的事件)event.target是注册事件时的元素(或子元素), 通过比较它与this来确定事件是否由冒泡触发。观察event.relatedTarget找到事件涉及的其他 DOM 元素event.relatedTarget对于mouseout事件,指向被进入的元素; 对于mouseover事件,指向被离开的元素事件处理函数的最后返回值会被记录在
event.result中event.timeStamp记录事件的时间戳1234567var last$('div').click(function(event) {if (last) {console.log(event.timeStamp - last); //打印两次点击时间差}last = event.timeStamp;});event.which将event.keyCode和event.charCode标准化了。用来监视鼠标和键盘输入
特殊
$.holdReady()方法允许调用者延迟 jQuery 的ready事件(在事件触发前)为了延迟
ready事件,首先要调用$.holdReady(true),当ready事件准备执行时,再调用$.holdReady(false)- 命名空间
event.namespace的用法123456$('p').bind('test.something', function (event) { // 绑定一个自定义事件alert(event.namespace); // event指向test});$("button").click(function(event) { // 通过浏览器事件来间接触发自定义命名事件$('p').trigger('test.something');});