WEB开发网
开发学院网页设计JavaScript Jquery源码分析---构建Jquery的Dom元素 阅读

Jquery源码分析---构建Jquery的Dom元素

 2010-09-14 13:36:44 来源:WEB开发网   
核心提示: 上面find的实现的代码有点长,其实分析起来也不是很难,Jquery源码分析---构建Jquery的Dom元素(10),①②③④⑤处两个if-else是元素选择器,针对>/+~ F或#id,.class tagName,div#id这样的选择器进行查找元素,找一个复杂的例子,自行分析

上面find的实现的代码有点长。其实分析起来也不是很难。①②③④⑤处两个if-else是元素选择器,针对>/+~ F或#id,.class tagName,div#id这样的选择器进行查找元素,构成结果集。⑥实现的就是分析它之后的属性选择器进行筛选。这段代码说白就是select与Filte之间的交互分析CSS selector的字符串进行查找或筛选的过程。

具体的细节在代码中有分析。在⑦处它采用先找到所有元素然后对每个元素进行class的判断来分析如.class这样selector。因为它在起始位说明是查找器。但是这里对这个最小的单元部分,我们还可能两个部分,找到所有元素,然后一个个排查,排查就是采用了jQuery.classFilter(r, m[2]):

classFilter : function(r, m, not) {
  m = " " + m + " ";//这里的做法就是怕出现如”class12”这样的问题
  var tmp = [];   //如果传的m= class1,这个的条件是满足的,实际是不。
  for (var i = 0;r[i]; i++) {
    var pass = (" " + r[i].className + " ").indexOf(m) >= 0;
    if (!not && pass || not && !pass)
      tmp.push(r[i]);
  }
  return tmp;
},

jQuery.classFilter是比较简单。在find()的第二个部分是筛选,它调用jQuery.filter(t, r)来完成功能:

//根据CSS selector表达式查找集合中满足该表达式的所有元素
//还可以根据not来指定不满足CSS selector表达式元素集
filter : function(t, r, not) {
  var last;
  while (t && t != last) {// t存在,且改变
    last = t;
    // Match: [@value='test'], [@foo]
    // 1、^([) *@?([w:-]+) *([!*$^~=]*) *('?"?)(.*?)4 *]/,
  
    // Match: :contains('foo')
    // 2、^(:)([w-]+)("?'?(.*?((.*?))?[^(]*?)"?'?)/,
  
    // Match: :even, :last-child, #id, .class
    // 3、new RegExp("^([:.#]*)(" + chars + "+)")],   
    //这里可以看出我们直接调用filter的时候的selector如不是筛选器的话,
    //那就不进行筛选了,这里的selector语法如[@value='test'], [@foo]、
    //:contains('foo'),:even, :last-child, #id, .class的形式
    //可以是上面这几种形式的组合,但不能包括元素选择器。
  //而且复合的形式中间不能采用空格隔开,如[@value='test']#id.class可行的。
    var p = jQuery.parse, m;
    for (var i = 0;p[i]; i++) {// 找到与jQuery.parse中regexp相配的
      m = p[i].exec(t);
      if (m) {
       t = t.substring(m[0].length);//删除处理过的字符部分
       m[2] = m[2].replace(//g, "");// 有可能会有没有转换的去掉
       break;
      }
    }    
    // 与上面三种的regexp都不相配
    if (!m)  break;
  
    //处理 :not(.class)的形式,返回集合中不包含.class的其它的元素
    if (m[1] == ":" && m[2] == "not")
      // 性能上优化 m[3]是.class经常出现
      r = isSimple.test(m[3])// isSimple = /^.[^:#[.]*$/
         ? jQuery.filter(m[3], r, true).r: jQuery(r).not(m[3]);
    //处理.class的过滤。只要看看m[2]这个class是不是被集合中元素的class包含。
    else if (m[1] == ".")// 性能上优化考虑
      r = jQuery.classFilter(r, m[2], not);
      //处理属性过滤。如[@value='test']形式的属性选择
    else if (m[1] == "[") {
      var tmp = [], type = m[3];// 符号,如=
  
      for (var i = 0, rl = r.length;i < rl; i++) {
       //jQuery.props[m[2]]进行tag中属性名和对应的元素的属性名转换,
       //因为tag中属性名是元素中简写,z取到 元素的属性值
       var a = r[i], z = a[jQuery.props[m[2]] || m[2]];
       //直接取元素的属性值,没有取到,说明有的浏览器不支持这种方法
       //进一步尝试采用jQuery.attr来进行非标准的兼容取属性值。
       //就算是取到了值,但对于属性名为style|href|src|selected,
       //它们不能直接取值,要进行特殊的处理,这个在jQuery.attr进行。
       //其实这里可以直接采用jQuery.attr(a, m[2]),一步到位。
       if (z == null || /style|href|src|selected/.test(m[2]))
         z = jQuery.attr(a, m[2]) || '';// 几个特殊的处理
  
      //如果属性选择器满足这
//[foo],[foo=aa][foo!=aa][foo^=aa][foo$=aa][foo~=aa]
       //这几种方式之一,这个元素就可能通过。即满足条件。m[5]属性值。
    if (  (type == "" && !!z//[foo]
     || type == "=" && z == m[5]//[foo=aa]
     || type == "!=" && z != m[5]//[foo!=aa]
     || type == "^=" && z&& !z.indexOf(m[5])//[foo^=aa]
     || type == "$=" && z.substr(z.length - m[5].length) == m[5]     || (type == "*=" || type == "~=")&& z.indexOf(m[5]) >= 0
       )
    ^ not)
      tmp.push(a);
      }
      r = tmp;
  
    }
    //处理:nth-child(n+1)。其实这里也改变了结果集,
    //不过这里是采用的是间接引用的方式,只要知道元素就可以了,
    //不需要dom树去查找。因为它要解析参数中的表达式
    else if (m[1] == ":" && m[2] == "nth-child") {// 性能考量
      var merge = {}, tmp = [],
    // 分析:nth-child(n+1)中的参数,这里支持
    //'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'几种形式
    //test[1]="-或空",test[2]="n前面的数或空",test[3]="n后面的数或空"
    //这样把参数分成三个部分:1是负号的处理,2是xn中的x处理,3是n-x中-x的处理
      //3中的是带有符号的。也就是+或-。
      test = /(-?)(d*)n((?:+|-)?d*)/.exec(m[3] == "even" && "2n"
         || m[3] == "odd" && "2n+1" || !/D/.test(m[3]) && "0n+"
         + m[3] || m[3]),
  
      // 计算(first)n+(last)
      first = (test[1] + (test[2] || 1)) - 0, last = test[3] - 0;
      //找到符合(first)n+(last)表达式的所有子元素
    for (var i = 0, rl = r.length;i < rl; i++) {
      var node = r[i], parentNode = node.parentNode,
    id = jQuery.data(parentNode);//为该元素parentNode分配了一个全局的id
  
      if (!merge[id]) {// 为元素的每个子节点标上顺序号,作了不重复标识
         var c = 1;
       for (var n = parentNode.firstChild;n; n = n.nextSibling)
           if (n.nodeType == 1)n.nodeIndex = c++;
         merge[id] = true;
       }
  
       var add = false;//初始化add的标记
       //常数的形式,如1,2等等,当然还要判断元素的序号和这个数是否相等。
       if (first == 0) {// 0不能作除数
         if (node.nodeIndex == last)
           add = true;
       }
       // 处理3n+2这种形式同时表达式要大于0
       //当前的子节点的序号要满足两个条件:
       //1、其序号进行first求余的结果=last.
       //2、其序号要大于last。对于-n的形式,要大于-last.
       else if ((node.nodeIndex - last) % first == 0
           && (node.nodeIndex - last) / first >= 0)
         add = true;
  
       if (add ^ not)  tmp.push(node);
      }
  
      r = tmp;
  
    }
    else {// 根据m[1]m[2]在Query.expr找到对应的处理函数
      var fn = jQuery.expr[m[1]];
      //支持一个符号(如:last)后的方法名与函数的对应
      if (typeof fn == "object")
       fn = fn[m[2]];
       //支持更简短的string来代替jQuery.expr中的funciton。
       //这里没有用到。
      if (typeof fn == "string")
       fn = eval("false||function(a,i){return " + fn + ";}");
  
    // 执行处理函数fn过滤。对于r中每个元素,如果fn返回的结果为true,保留下来。
      r = jQuery.grep(r, function(elem, i) {
       return fn(elem, i, m, r);
      }, not);
    }
  }
  return {
    r : r,
    t : t
  };
},

jQuery.filter完成分析属性([])、Pseudo(:),class (.),id(#),的筛选的功能。从给定的集合中筛选出满足上面四种筛选表达式的集合。针对于find()。这个filter完成不表明整个selector的分析完成了。还会交替地通过查找器来查找或通过该函数来筛选。对于单独使用这个函数,表达式中就不应该含有查找的selector表达式了。筛选是根据[、:、#、.这四个符号来做为筛选器的分隔符的。

class筛选器是通过classFilter来完成。它还把Pseudo中:not、:nth-child单独从Pseudo类的中单独提起出来处理。对于[的属性筛选器,实现起来也是很简单。除去这些,它还调用jQuery.expr[m[1]];来处理Pseudo类,而jQuery还做了扩展。jQuery.expr中的Pseudo类有以下几个部分:// Position Checks、// Child Checks、// Parent Checks、// Text Check、// Visibility、// Form attributes、// Form elements、// :has()、// :header、// :animated。也就是说在CSS selector中,我们可以采用Pseudo类提供上面这些类别的方法来进行筛选。其代码就是一些判断,不作分析。

如果想详细了解这样怎么用吧,推荐由一揪整理编辑jquery的中文文档。,

对于CSS selector,尽管多次分析domQuery,和jquery Selector。尽管自己也吃透。但是感觉到写出来还是不到位。如果读者之前没有接受这方面。建议仔细分析上面的代码和注释。找一个复杂的例子,自行分析一下,或许可能弄懂selector的设计。

文章来源:http://jljlpch.javaeye.com/category/37744

上一页  5 6 7 8 9 10 

Tags:Jquery 源码 分析

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接