经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JS/JS库/框架 » jQuery » 查看文章
jQuery 源码分析(十九) DOM遍历模块详解
来源:cnblogs  作者:大沙漠  时间:2019/11/4 8:43:35  对本文有异议

jQuery的DOM遍历模块对DOM模型的原生属性parentNode、childNodes、firstChild、lastChild、previousSibling、nextSibling进行了封装和扩展,用于在DOM树中遍历父元素、子元素和兄弟元素。

可以通过jQuery的实例来访问,方法如下:

  •   parent()                  ;获取匹配元素的父元素                
  •   parents(selector)           ;获取匹配元素的所有祖先元素                                    ;selector用于过滤查找的元素,如果为空则获取所有的祖先元素            
  •   parentsUntil(until,selector)    ;获得当前匹配元素集合中每个元素的祖先元素,直到遇到until元素        
  •   next()                     ;获取匹配元素之后紧挨着的兄弟元素,没有则返回undefined
  •   nextAll(selector)               ;获取匹配元素之后紧挨着的所有兄弟元素             
  •   nextUntil(until,selector)       ;获取匹配元素之后紧挨着的所有兄弟元素,直到遇到until元素 
  •   prev()                    ;获取匹配元素之前紧挨着的兄弟元素,没有则返回undefined
  •   prevAll(selector)              ;获取匹配元素之前紧挨着的所有兄弟元素             
  •   prevUntil(until,selector)        ;获取匹配元素之前紧挨着的所有兄弟元素,直到遇到until元素     
  •   siblings(selector)            ;获取匹配元素的所有兄弟元素,如果指定了selector则只获取该类型的元素 
  •   children(selector)           ;获取匹配元素的子元素,不包括文本节点和注释节点         
  •   contents()                  ;获取匹配元素的子元素,包括文本节点和注释节点 

举个栗子:

 writer by:大沙漠 QQ:22969969

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Document</title>
  6. <script src="http://libs.baidu.com/jquery/1.11.1/jquery.min.js"></script>
  7. </head>
  8. <body>
  9. <div>
  10. <h1>Hello World!</h1>
  11. <p>123</p>
  12. <span>123</span>
  13. </div>
  14. <script>
  15. console.log( $('p').parent() ) //获取p元素的父元素
  16. console.log( $('p').prev() ) //获取p元素之前紧挨的兄弟元素
  17. console.log( $('p').next() ) //获取p元素之后紧挨的兄弟元素
  18. console.log( $('p').siblings() ) //获取p元素的所有兄弟元素
  19. console.log( $('div').children() ) //获取div的所有子元素,不包括文本节点和注释节点
  20. console.log( $('div').contents() ) //获取div的所有子元素,包括文本节点和注释节点
  21. </script>
  22. </body>
  23. </html>

输出如下:

 对应栗子里的每一个输出,分别输出

  • p元素的父节点
  • p元素的上一个兄弟元素
  • p元素的下一个兄弟元素
  • p元素的所有兄弟元素
  • div元素过滤掉文本节点和空白节点的子节点
  • div元素包括文本节点和空白节点的子节点

返回的都是一个jQuery对象,非常的好用,操作DOM时都会用到这几个方法

 

源码分析


 jQuery对于DOM遍历模块的实现是基于三个工具函数实现的

  • $.dir(elem, dir, until)       ;从elem元素开始,查找dir方向(可以是:parentNode、nextSibling或previousSibling)上的所有元素,如果在查找过程中遇到匹配参数until的元素,则查找终止
  • $.nth(cur, result, dir, elem)  ;从cur元素出发,查找dir方向(parentNode、nextSibling或previousSibling)上的第result个元素
  • $.sibling(n, elem)       ;负责查找一个元素之后的所有兄弟元素,包括起始元素,但不包括参数elem。n是查找的起始元素,包含在结果集中,elem是可选的DOM元素,不包含在返回结果中。

举个栗子:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Document</title>
  6. <script src="http://libs.baidu.com/jquery/1.7.1/jquery.min.js"></script>
  7. </head>
  8. <body>
  9. <div>
  10. <h1>Hello World!</h1>
  11. <p>123</p>
  12. <span>123</span>
  13. </div>
  14. <script>
  15. var h1 = document.getElementsByTagName('h1')[0], //分别获取h1、p、span元素的节点引用
  16. p = document.getElementsByTagName('p')[0],
  17. span = document.getElementsByTagName('span')[0];
  18. console.log( $.dir(h1,'parentNode') ) //打印h1的所有祖先节点
  19. console.log( $.nth(h1,3,'nextSibling') ) //获取h1之后的第二个节点
  20. console.log( $.sibling(h1,h1) ) //获取h1的所有兄弟元素,默认获取包括自身在内的元素,参数2也传入h1表示排除h1元素
  21. </script>
  22. </body>
  23. </html>

输出如下:

输出三行,分别对应h1的所有祖先节点、h1之后的第二个子节点和h1的所有兄弟元素,和DOM树中也是对应的。

对于$.dir、$.nth和$.sibling来说,它的实现如下:

  1. jQuery.extend({
  2. dir: function( elem, dir, until ) { //从elem元素开始,查找dir方向(可以是:parentNode、nextSibling或previousSibling)上的所有元素,如果在查找过程中遇到匹配参数until的元素,则查找终止。
  3. var matched = [],
  4. cur = elem[ dir ]; //cur表示下一个元素,根据参数dir不同,可能是父元素、前一个兄弟元素 或者 后一个兄弟元素
  5.  
  6. while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { //如果下一个元素存在 且 不是document对象(nodeType等于9) 则继续判断括号里的语句,否则跳出循环 括号内:如果没有传入until参数,或者传入了until参数并且当前元素不是Element节点(属性nodeType等于1) 或者 传入了until参数且当前参数是Element节点且该元素不匹配参数until 则进行循环
  7. if ( cur.nodeType === 1 ) { //如果cur是元素节点
  8. matched.push( cur ); //存储到数组matched中
  9. }
  10. cur = cur[dir]; //获取下一个方向上的元素
  11. }
  12. return matched; //返回找到了的Element节点数组。
  13. },
  14. nth: function( cur, result, dir, elem ) { //从cur元素出发,查找dir方向(parentNode、nextSibling或previousSibling)上的第result个元素
  15. result = result || 1;
  16. var num = 0; //当前查找的元素序号
  17.  
  18. for ( ; cur; cur = cur[dir] ) { //从起始元素cur触发,沿着方向dir迭代遍历,只要cur元素存在则一直查找,直到查找该方向上的第result个Element节点
  19. if ( cur.nodeType === 1 && ++num === result ) { //如果cur是一个元素节点,则num+1,此时如果num等于result,则表示查找到该元素了,则跳出循环
  20. break;
  21. }
  22. }
  23. return cur; //返回查找到的cur元素。
  24. },
  25. sibling: function( n, elem ) { //负责查找一个元素之后的所有兄弟元素,包括起始元素,但不包括参数elem。n是查找的起始元素,包含在结果集中,elem是可选的DOM元素,不包含在返回结果中。
  26. var r = [];
  27. for ( ; n; n = n.nextSibling ) { //从起始元素n触发,迭代遍历其后的所有兄弟元素
  28. if ( n.nodeType === 1 && n !== elem ) { //如果该兄弟元素是元素节点且不等于参数elem则被放入数组r中。
  29. r.push( n );
  30. }
  31. }
  32. return r; //返回存放了找到的Element节点的数组r
  33. }
  34. });

也就是对parentNode、childNodes、firstChild、lastChild、previousSibling、nextSibling这些原生DOM操作的一些封装

我们通过jQuery实例可以访问的方法的实现如下:

  1. jQuery.each({
  2. parent: function( elem ) { //返回匹配元素的父元素
  3. var parent = elem.parentNode;
  4. return parent && parent.nodeType !== 11 ? parent : null; //如果父元素存在且不是文档碎片元素,则返回该父元素,否则返回null
  5. },
  6. parents: function( elem ) { //返回匹配元素的所有祖先元素
  7. return jQuery.dir( elem, "parentNode" );
  8. },
  9. parentsUntil: function( elem, i, until ) { //获得当前匹配元素集合中每个元素的祖先元素,直到遇到until元素
  10. return jQuery.dir( elem, "parentNode", until );
  11. },
  12. next: function( elem ) { //获取匹配元素之后紧挨着的兄弟元素
  13. return jQuery.nth( elem, 2, "nextSibling" );
  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. prevAll: function( elem ) { //获取匹配元素之前紧挨着的所有兄弟元素
  22. return jQuery.dir( elem, "previousSibling" );
  23. },
  24. nextUntil: 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. siblings: function( elem ) { //获取匹配元素的所有兄弟元素
  31. return jQuery.sibling( elem.parentNode.firstChild, elem );
  32. },
  33. children: function( elem ) { //获取匹配元素的子元素
  34. return jQuery.sibling( elem.firstChild );
  35. },
  36. contents: function( elem ) { //获取匹配元素的子元素,包括文本节点和注释节点
  37. return jQuery.nodeName( elem, "iframe" ) ?
  38. elem.contentDocument || elem.contentWindow.document :
  39. jQuery.makeArray( elem.childNodes );
  40. }
  41. }, function( name, fn ) { //模板函数,用于调用对应的遍历函数查找DOM元素,然后执行过滤、排序、和去重操作 name是每个函数名,fn是对应的值(也就是函数)
  42. jQuery.fn[ name ] = function( until, selector ) { //定义模版函数,真正是在这里定义的,它接收两个参数 until:选择器表达式,用于指示查找停止的位置。selector:选择器表达式,用于过滤找到的元素
  43. var ret = jQuery.map( this, fn, until ); //调用方法jQuery.map()遍历当前匹配元素集合,对每个元素调用遍历函数fn,并将遍历函数fn的返回值放入一个新的数组ret中。
  44.  
  45. if ( !runtil.test( name ) ) { //如果遍历函数名不以'Until'结尾的,则最多只有一个参数
  46. selector = until; //修正参数selector为until
  47. }
  48. if ( selector && typeof selector === "string" ) { //如果设置了参数selector 且selector是一个字符串
  49. ret = jQuery.filter( selector, ret ); //则调用jQuery.filter()对数组ret中的DOM元素逐个过滤,最终只保留匹配选择器表达式selector的元素。
  50. }
  51. ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
  52. if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { //排序
  53. ret = ret.reverse();
  54. }
  55. return this.pushStack( ret, name, slice.call( arguments ).join(",") ); //创建一个jQuery对象并返回
  56. };
  57. });

实现就是通过$.each()遍历一个对象,依次执行参数2这个函数,该函数会在$.fn上依次挂载每个接口,使用$.map()工具方法它会依次执行fn函数,进行一些过滤去重后最后调用$.pushStack()将数组转换为一个jQuery对象,这里理解起来有点难度,需要多理一下代码。

原文链接:http://www.cnblogs.com/greatdesert/p/11724756.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号