jQuery DOM遍历:
childNodes:包含HTML元素 文本。
children: 只包含HTML元素。
jQuery.fn.children(elem):只包含Elemnet
jQuery.fn.contents(elem):只含Element Text Comment
实现jQuery遍历的具体方法:
1 jQuery.each({ 2 parent:function(elem){//父元素 3 var parent = elem.parentNode; 4 return parent && parent.nodeType !== 11 ? parent : null;//DocumentFragment 11,DocumentType 10 5 }, 6 parents:function(elem){ 7 return jQuery.dir(elem,"parentNode");//检索所有父元素,直至document 8 }, 9 parentsUntil:function(elem,i,until){ 10 return jQuery.dir(elem,"parentNode",until); 11 }, 12 next:function(elem){//下一个兄弟元素 13 return jQuery.nth(elem,2,"nextSibling");//从1开始计数,当前为1 14 }, 15 prev:function(elem){//上一个兄弟元素 16 return jQuery.nth(elem,2,"previousSibling"); 17 }, 18 nextAll:function(elem){//所有的兄弟元素 19 return jQuery.dir(elem,"nextSibling"); 20 }, 21 prveAll:function(elem){//所有兄长元素 22 return jQuery.dir(elem,"previousSibling"); 23 }, 24 nextUnitl:function(elem,i,until){//所有的兄弟元素,但不包括until 25 return jQuery.dir(elem,"nextSibling",until); 26 }, 27 prevUntil:Function(elem,i,until){//所有的兄长元素,但不包括until 28 return jQuery.dir(elem,"previousSibling",until); 29 }, 30 31 siblings:function(elem){//所有的兄长,兄弟元素 不包括当前元素 32 // 父元素的第一个子元素的所有兄弟元素,排除当前元素elem 33 // 取子元素childNodes然后过滤elem,效率更高 34 return jQuery.sibling(elem.parentNode.firstChild,elem); 35 }, 36 children: function( elem ) { // 所有的子节点,只包含Element 37 return jQuery.sibling( elem.firstChild ); // 第一个子元素的所有兄弟元素 38 // 为什么不直接取子元素呢?childNodes不是效率更高么? 39 }, 40 contents: function( elem ) { // 所有的子节点,包含Element、Text、Comment 41 return jQuery.nodeName( elem, "iframe" ) ? 42 elem.contentDocument || elem.contentWindow.document : // 如果是iframe,则取document 43 jQuery.makeArray( elem.childNodes ); // 将childNodes转换数组,childNodes是伪数组,转换后遍历数组时可以避免对childNodes进行检查,提高性能 44 } 45 },function(name,fn){ 46 jQuery.fn[name] = function(until,selector){ 47 var ret = jQuery.map(this,fn,until),//将this中的元素,用fn处理最后返回真正的数组 until用于过滤 48 args = slice.call(arguments);//将arguments赋值并转为数组 49 if(!runtil.test(name)){//不以until结尾 50 selector = until;//不需要参数until 只有一个参数selector util知道这里为止 51 } 52 if(selector && typeof selector === "string"){ 53 ret = jQueyr.filter(selector,ret);//对ret数组用selector进行过滤 只留下匹配的元素 54 // jQuery.filter会调用jQuery.find.matches > Sizzle.matches > Sizzle,Sizzle查找、过滤的结果已经经过排序、去重 55 } 56 /** 57 * 排序、去重 58 * 首先要知道this是经过排序、且无重复 59 * 如果长度大于1,才需要判断是否需要去重 60 * 如果name是 children contents next prev 之一,则不需要排序去重,因为这四个方法不会产生无序和重复的结果,为什么呢? 61 * 因为this中的元素是有序、去重的,所以的它子节点、兄弟、兄长,也都是有序、无重复的 62 * 但是parent parents parentsUntil nextAll prevAll nextUntil prevUntil siblings却有可能产生重复、无序的元素 63 */ 64 ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; // 去重 65 66 // rparentsprev = /^(?:parents|prevUntil|prevAll)/ 67 // 因为前边返回的结果是按照元素在文档中的位置顺序返回的,遇到rparentsprev则需要再反过来,方便使用 68 if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { 69 ret = ret.reverse(); // 倒序 70 } 71 72 return this.pushStack( ret, name, args.join(",") ); // 构造jQuery对象 73 } 74 });
DOM遍历的三个核心方法:
DOM遍历的三个核心函数:
jQuery.dir(elem,dir,until) :从一个元素触发,迭代检索某个方向上的所有元素并记录,知道与遇到docuemnt对象或遇到until匹配的元素
jQuery.nth(cur,result,dir,elem) :从一个元素触发,迭代检索某个方向上的第N个元素
jQuery.sibling(n,elem) :元素n的所有后续兄弟元素,包含n,不包含elem
1 jQuery.extend({ 2 /* 3 DOM遍历的三个核心函数: 4 jQuery.dir(elem,dir,until) :从一个元素触发,迭代检索某个方向上的所有元素并记录,知道与遇到docuemnt对象或遇到until匹配的元素 5 jQuery.nth(cur,result,dir,elem) :从一个元素触发,迭代检索某个方向上的第N个元素 6 jQuery.sibling(n,elem) :元素n的所有后续兄弟元素,包含n,不包含elem 7 8 */ 9 /* 10 迭代条件:cur.nodeType !== 9 && !jQuery(cur).is(until) 11 elem: 起始元素 12 dir: 迭代方向,可选值:parentNode nextSibling previousSibling 13 until 选择器表达式 如果遇到until匹配的元素 迭代终止 14 */ 15 dir:function(elem,dir,until){//支持遍历祖先 所有兄长 所有兄弟 16 var matched = [],//匹配结果 17 cur = elem[dir];//第一次访问 在dir方向上取一次 为循环提供第一次判断 18 //不包含自身 19 /* 20 迭代访问 知道遇到document对象或遇到until匹配的元素 21 cur.nodeType !== 9 当前DOM节点cur不是document对象 nodeType = 1 是element 22 !jQuery(cur).is(until) 当前DOM节点cur不匹配表达式until 23 24 这里或运算的过程中 满足这个条件until !==undefined && cur.nodeType ===1才会调用jQuery.is 25 */ 26 while(cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery(cur).is(until))){ 27 if(cur.nodeType === 1){//如果是Element元素 则放入匹配结果数组 28 matched.push(cur);//符合要求 放入数组 29 } 30 cur = cur[dir];//将方向dir上的下一个节点 设置为当前节点 继续访问 31 } 32 return matched; 33 }, 34 /* 35 从一个元素触发,迭代检索某个方向上的第N个元素 36 37 cur 起始元素 38 result第几个 1表示当前元素 2表示下一个 39 dir 迭代方向 40 elem 多余 41 */ 42 nth:function(cur,result,dir,elem){ 43 result = result || 1;//默认为从1开始 44 var num =0; 45 46 for(;cur;cur = cur[dir]){//先判断再取,结果中包含n 47 //检索到了这个元素 48 if(cur.nodeType === 1 && ++ num === result){ 49 break; 50 } 51 } 52 //如果result为0 或者1 取当前元素 53 //如果result小于0 则放回undefined 54 return cur; 55 }, 56 /* 57 元素n的所有后续兄弟元素 包含n 不包含elem 58 n 起始元素 59 elem排除元素 60 */ 61 sibling:function(n,elem){ 62 var r = []; 63 for(;n;n = n.nextSibling){//先判断再取,结果中包含n 64 //过滤掉其他的Text Attr Comment等元素 65 if(n.nodeType === 1 && n !== elem){ 66 r.push(n); 67 } 68 } 69 return r; 70 } 71 });