[原创] jQuery源码分析-11 DOM遍历-Traversing-3个核心函数
作者:nuysoft/高云 QQ:47214707 Email:nuysoft@gmail.com
声明:本文为原创文章,如需转载,请注明来源并保留原文链接。
1. DOM遍历有3个核心函数:
jQuery.dir( elem, dir, until ) | 从一个元素出发,迭代检索某个方向上的所有元素并记录,直到与遇到document对象或遇到until匹配的元素 |
jQuery.nth( cur, result, dir, elem ) | 从一个元素出发,迭代检索某个方向上的第N个元素 |
jQuery.sibling( n, elem ) | 元素n的所有后续兄弟元素,包含n,不包含elem |
jQuery对象上的DOM遍历方法(大部分)被转换对这3个核心函数的调用,而这3个核心函数最后又都转换为对原生API的操作,看看他们之间的关系:
核心函数 | jQuery对象方法 | 含义 | 用到的原生API |
jQuery.dir | parents | 祖先元素 | parentNode |
parentsUntil | 祖先元素,但是不包括until | parentNode | |
nextAll | 所有的兄弟元素 | nextSibling | |
prevAll | 所有的兄长元素 | previousSibling | |
nextUntil | 所有的兄弟元素,但是不包括until | nextSibling | |
prevUntil | 所有的兄长元素,但是不包括until | previousSibling | |
jQuery.nth | next | 下一个兄弟元素 | nextSibling |
prev | 上一个兄长元素 | previousSibling | |
jQuery.sibling | siblings | 所有兄长、兄弟元素,不包括当前元素 | elem.parentNode.firstChild |
children | 所有的子节点 | elem.firstChild |
2. jQuery.dir( elem, dir, until )
/** * 从一个元素出发,迭代检索某个方向上的所有元素并记录,直到与遇到document对象或遇到until匹配的元素 * 迭代条件(简化):cur.nodeType !== 9 && !jQuery( cur ).is( until ) * elem 起始元素 * dir 迭代方向,可选值:parentNode nextSibling previousSibling * until 选择器表达式,如果遇到until匹配的元素,迭代终止 */ dir: function( elem, dir, until ) { // 这个函数很精髓,短短几行代码,支持遍历祖先、所有兄长、所有兄弟! var matched = [], // 匹配结果 cur = elem[ dir ]; // 第一次访问,尝试在方向dir上取一次,为循环提供第一次判断(变量cur多余,只用elem就可满足) // 不包含自身 /** * 迭代访问,直到遇到document对象或遇到until匹配的元素 * cur.nodeType !== 9 当前DOM节点cur不是document对象 * !jQuery( cur ).is( until ) 当前DOM节点cur不匹配表达式until * * until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until ) * 这个布尔表达式也有点意思,执行最后的jQuery.is的隐含条件是:until !== undefined && cur.nodeType === 1 * 复合的布尔表达式和三元表达式,能减少代码行数、稍微提升性能,但是代码晦涩,不易阅读和维护。 * 也许看不懂也是jQuery风靡的原因之一 */ while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { if ( cur.nodeType === 1 ) { // 如果是Element,则放入匹配结果数组 matched.push( cur ); } cur = cur[dir]; // 将方向dir上的下一个节点,设置为当前节点,继续访问 } return matched; } |
3. jQuery.nth( cur, result, dir, elem )
/** * 从一个元素出发,迭代检索某个方向上的第N个元素 * cur 起始元素 * result 第几个,1表示当前元素,2表示下一个,以此类推(搞不明白为什么从1开始?) * dir 迭代方向 * elem 多余 */ nth: function( cur, result, dir, elem ) { result = result || 1; // 第几个?默认从1开始?嗯,这里从1开始计数,1表示当前元素,2表示下一个,以此类推 var num = 0; // 操蛋的初始值,初始为1更好理解 // 下边的for循环看的蛋疼! // dir先在方向dir上取一次再循环,nth先循环一次然后再取 // dir不包含自身,nth包含自身 for ( ; cur; cur = cur[dir] ) { // 某个方向 if ( cur.nodeType === 1 && ++num === result ) { // 先加后取值,num等于1时检查的是当前元素 break; } } // 如果result为0或1,则取当前元素 // 如果result小于0,则返回undefined return cur; } |
4. jQuery.nth( cur, result, dir, elem )
/** * 元素n的所有后续兄弟元素,包含n,不包含elem * n 起始元素(包含在返回结果中) * elem 排除元素 */ sibling: function( n, elem ) { var r = []; for ( ; n; n = n.nextSibling ) { // 先判断再取,结果中包含n // nodeType === 1,只能是Element,过滤了其他的Text、Attr、Comment等元素 if ( n.nodeType === 1 && n !== elem ) { r.push( n ); } } return r; } |