zoukankan      html  css  js  c++  java
  • jQuery源码分析系列:DOM遍历方法

    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 });

     

     

     

  • 相关阅读:
    java操作Redis
    Redis安装和基本操作
    IDEA使用教程+JRebel破解
    java环境配置
    qtp10安装步骤(比较完整)
    c++第一章1.6
    软件测试第二章作业
    c++作业22题
    c++第二周阶段小测2
    oracle12c数据库第一周小测验
  • 原文地址:https://www.cnblogs.com/colorstory/p/2621675.html
Copyright © 2011-2022 走看看