asfman
android developer
posts - 90,  comments - 213,  trackbacks - 0

 var chars = jQuery.browser.safari && parseInt(jQuery.browser.version)<417?"(?:[\\w*_-]|\\\\.)":"(?:[\\w\u0128-\uFFFF*_-]|\\\\.)",
 //包括中英文* _ -\.的任意单个字符
 quickChild = new RegExp("^>\\s*(" + chars + "+)"), //匹配以>开始的,后面至少有一个字符的内容,如>child,> child
 quickID = new RegExp("^(" + chars + "+)(#)(" + chars + "+)"),//匹配如nodeName#idName
 quickClass = new RegExp("^([#.]?)(" + chars + "*)");//匹配如#idName, .className, nodeName

 //多重过滤函数,对已有的dom元素进行多重过滤,elems可以是dom元素数组[dom1,dom2..],也可以是jq实例{0:dom1, 1: dom2...}
 //多重过滤的意思,也就是expr可以是以,分开的n个过滤表达式如,".a,.b,:odd",not参数为true的话,表示返回除了找到的元素以外的元素
 multiFilter: function( expr, elems, not ) {
   var old, cur = [];
   //old每次过滤前保存表达式字符串,用来与过滤后expr进行比较,如果两者相同,表示过滤循环结束
   while ( expr && expr != old ) {
    old = expr;
    var f = jQuery.filter( expr, elems, not );//其实多重过滤是把以,分开的表达式进行filter函数处理,所以过滤的最核心函数是filter函数
    expr = f.t.replace(/^\s*,\s*/, "" );//一次过滤结束后,如果是多重的话,返回肯定是",xxx",所以得把“,”替换掉以进行下一次过滤
    cur = not ? elems = f.r : jQuery.merge( cur, f.r );//elems保存返回的dom数组,因为not为true的话,
    下一次过滤肯定是从返回的dom数组里进行再一次的过滤,如果not不存在,则用cur和返回数组进行合并,
    不改变elems,因为返回只是一次过滤成功的元素,所以elems不变,但这会存在一个问题,
    如<div class="a b"></div>如果expr为".a, .b"那么第一次返回数组里有这个dom对象,第二次又会有这个对象,所以得进行unique处理
   }

   return cur;//而jq这里对最终结果没有处理!所以会出现上面所说的情况,最终返回dom数组里有可能包含同一个dom元素n次。
  }

 下面听asfman来着重讲解一下jq的过滤核心函数filter函数
 //filter函数所用到的正则表达式
  jQuery.parse=[ 
   /^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,// 匹配如[@value='test'], [@foo] 
   /^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,// 匹配如:contains('foo'),:has('.a'),:nth-child(4n)  
   new RegExp("^([:.#]*)(" + chars + "+)")//匹配如:even, :last-child, #id, .class,  nodeName
  ]
 filter: function(t,r,not) {//t为过滤表达式如".a", ".a.b", "#id","nodeName","[attr=value]",":nth-child(4n)"等等
   var last;
   while ( t && t != last ) {
    last = t;//用来保存上一次过滤钱的表达式,如果last和t相同则结束循环
    var p = jQuery.parse, m;
    for ( var i = 0; p[i]; i++ ) {//对parse数组进行遍历
     m = p[i].exec( t );//m保存匹配结果m[1]为"[",":", ".","#"或者为空
     if ( m ) {//如果m存在则停止遍历
      t = t.substring( m[0].length );//移除匹配到的表达式如t为".a.b"那么匹配到.a后,t为".b"
      m[2] = m[2].replace(/\\/g, "");//如果m[2]中存在\那么就替换掉
      break;
     }
    }
    if ( !m )
     break;//如果遍历完parse后,m仍旧为null的话,那么此次过滤完全结束,执行while以后的代码
      //:not是一个非常特殊的表达式,jq对它进行了优化处理
    if ( m[1] == ":" && m[2] == "not" )
     r = isSimple.test( m[3] ) ?
     //判断m[3],也就是:not(nodeName),
     因为isSimple = /^.[^:#\[\.]*$/,它表示除了:#[.以外的任意字符,也就是简单的nodeName或者*,那么进行
     jQuery.filter(nodeName, r, true)进行简单过滤,也就是new RegExp("^([:.#]*)(" + chars + "+)")/
     会匹配到,然后返回不包含此nodeName的所有元素
      jQuery.filter(m[3], r, true).r :
      //:not(.a),:not([attr=value])的复杂类型的情况进行jQuery(r).not(m[3])处理
      jQuery( r ).not( m[3] );
 /*
  not: function( selector ) {
   if ( selector.constructor == String )
    // test special case where just one selector is passed in
    if ( isSimple.test( selector ) )
     return this.pushStack( jQuery.multiFilter( selector, this, true ) );
    else//也就是进行这步处理,以m[3]为.a为例,那么这里返回所有包含.a的dom元素
     selector = jQuery.multiFilter( selector, this );
   var isArrayLike = selector.length && selector[selector.length - 1] !== undefined && !selector.nodeType;
   return this.filter(function() {//此函数的第一个参数为i,this为dom元素, 如果这个dom元素不在包含.a的dom数组
   内,那么返回该元素,也就是说返回所有不包含.a的元素
    return isArrayLike ? jQuery.inArray( this, selector ) < 0 : this != selector;
   });
  }  
  filter: function( selector ) {
   return this.pushStack(
    jQuery.isFunction( selector ) &&
    jQuery.grep(this, function(elem, i){
     return selector.call( elem, i );
    }) ||

    jQuery.multiFilter( selector, this ) );
  }
 */
    else if ( m[1] == "." )//如果m[1]为.那么它肯定是过滤.className
     r = jQuery.classFilter(r, m[2], not);//r为dom数组,m[2]为className
 /*
 //对dom数组里的元素进行className的过滤,如m为".a"那么返回所有className包含.a的元素,
 如果not为true,那么返回所有className不包含.a的元素。
 classFilter: function(r,m,not){//r为dom数组或jq实例,m为className,not表示返回是否包含某个className的元素
   m = " " + m + " ";//className前后加空格是为了防止如className为"ab", 这样m为a的话也算包含a了,而通过" a "可以避免这种情况
   var tmp = [];//保存返回dom元素的数组
   for ( var i = 0; r[i]; i++ ) {//进行遍历处理,判断dom元素是否包含这个class
    var pass = (" " + r[i].className + " ").indexOf( m ) >= 0;
    if ( !not && pass || not && !pass )//not不存在,并且找到了,或者not为true,没找到的情况临时数组保存该dom元素
     tmp.push( r[i] );//这里也可以通过if(!!not^pass)进行异或来判断
   }
   return tmp;
  }
 */
    else if ( m[1] == "[" ) {//如果m[1]为[,那么它就是过滤属性的
    ///^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,// 匹配如[@value='test'], [@foo] 
     var tmp = [], type = m[3];//m[3]也就是包含!= ^= $= ~=这些
     for ( var i = 0, rl = r.length; i < rl; i++ ) {//遍历dom数组
      var a = r[i], z = a[ jQuery.props[m[2]] || m[2] ];
     //jQuery.props[m[2]]返回真是的属性名字,如果props返回为undefined那么z=a[m[2]],如elem.readOnly
 /*
  props: {
   "for": "htmlFor",
   "class": "className",
   "float": styleFloat,
   cssFloat: styleFloat,
   styleFloat: styleFloat,
   readonly: "readOnly",
   maxlength: "maxLength",
   cellspacing: "cellSpacing"
  }
 */
      if ( z == null || /href|src|selected/.test(m[2]) )
      //如果z不存在或者m[2]是href|src|selected中毒一个
       z = jQuery.attr(a,m[2]) || '';//通过attr函数再去找看是否是elem.style的属性,存在返回,不存在返回空字符串

      if ( (type == "" && !!z ||//如果!= ^= $= ~=不存在并且z存在[name]
        type == "=" && z == m[5] ||//如果type为=,z存在,并且z == xxx如[name=xxx]
        type == "!=" && z != m[5] ||//如果type为!=,z存在,并且z != xxx如[name!=xxx]
        type == "^=" && z && !z.indexOf(m[5]) ||如果type为^=,z存在,并且z中能找到m[5]开始,z.indexOf(xxx)如[name^=xxx]
        type == "$=" && z.substr(z.length - m[5].length) == m[5] ||//以m[5]结束
        (type == "*=" || type == "~=") && z.indexOf(m[5]) >= 0)//z中能找到m[5]
        ^ not )//就行异或,not为true则返回以上条件为false的元素,not不存在则返回以上结果为true的元素
        tmp.push( a );
     }

     r = tmp;//循环结果r保存过滤到的元素数组
    } else if ( m[1] == ":" && m[2] == "nth-child" ) {///^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,// 匹配:nth-child(4n)  
     var merge = {}, tmp = [],//merge用来避免取到相同元素
      test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(//匹配 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'等
       m[3] == "even" && "2n" || m[3] == "odd" && "2n+1" ||//如:nth-child(even)则even变为2n,odd为2n+1
       !/\D/.test(m[3]) && "0n+" + m[3] || m[3]),//如果为nth-child(3)则3变为0n+3
      first = (test[1] + (test[2] || 1)) - 0, last = test[3] - 0;//如2n+1那么first为2,last为1,如0n+3那么first为0,last为3
      //如果test[2]为0的话,因为这里0是个字符串所以"0"||1仍旧返回0,只有当test[2]不存在的情况才为1,也就是如n,n+1这种
     //遍历dom数组
     for ( var i = 0, rl = r.length; i < rl; i++ ) {
      var node = r[i], parentNode = node.parentNode, id = jQuery.data(parentNode);
      //node保存dom元素,parentNode保存dom元素的父元素,id为该父元素的expando属性的值
      if ( !merge[id] ) {//判断此父元素是否被遍历,防止重复遍历。
       var c = 1;/

       for ( var n = parentNode.firstChild; n; n = n.nextSibling )
        if ( n.nodeType == 1 )
         n.nodeIndex = c++;
    //对每个元素进行处理,用nodeIndex来保存元素所在父元素的位置,如第一个则nodeIndex为1
       merge[id] = true;
      }

      var add = false;//add用来表示是否满足条件

      if ( first == 0 ) {//如果first为0也就是:nth(3)这种情况
       if ( node.nodeIndex == last )//如果当前元素的nodeIndex等于last 则add为true
        add = true;
      } else if ( (node.nodeIndex - last) % first == 0 && (node.nodeIndex - last) / first >= 0 )
      //如2n+1,那么当nodeIndex为3-1%2 == 0时,add为true,如2n+3, 1 - 3 / 2 == -1是不成立的
       add = true;

      if ( add ^ not )//进行异或,把满足条件的元素推进tmp数组
       tmp.push( node );
     }

     r = tmp;
      //除了:not(.a), .className, [name = xxx] :nth-child(2n+1),这些情况外的进行以下处理
    } else {
     var fn = jQuery.expr[ m[1] ];//m[1]可以为"", ":", "#",fn也就是jQuery.expr[""],jQuery.expr["#"],jQuery.expr[":"]
 /*
  expr: {
    //new RegExp("^([:.#]*)(" + chars + "+)")//匹配如 m[1]为空,m[2]为nodeName或者"*"
   "": function(a,i,m){return m[2]=="*"||jQuery.nodeName(a,m[2]);},
   //a为elem, i为index, m为匹配到的数组, r为需要过滤的数组,如果m[2]为*,或者a的nodeName为m[2]
   //如filter("div", r), filter("*",r)
   "#": function(a,i,m){return a.getAttribute("id")==m[2];}//m[2]为id的值
   }
 */
     if ( typeof fn == "object" )
      fn = fn[ m[2] ];
 //如果fn为对象也就是jQuery.expr[":"]这种情况,fn为jQuery.expr[":"][m[2]]
 ,如jQuery.expr[":"]["first-child"]=function(a){return a.parentNode.getElementsByTagName("*")[0]==a;},
 所以我们可以很容易对expre[":"]进行扩展,如jQuery.expr[":"].fk = function(elem, i, m){return elem.fk == m[3];}
 :fk(you)匹配<div fk="you"></div>
     if ( typeof fn == "string" )//如果fn为字符串,如jQuery.expr[":"].name ="a.name == arguments[3][3]"
      fn = eval("false||function(a,i){return " + fn + ";}");
     r = jQuery.grep( r, function(elem, i){//通过grep来得到符合条件的元素
      return fn(elem, i, m, r);
     }, not );
    }
   }
   return { r: r, t: t };
   //返回过滤后的dom数组,和截取后的t,如t = t.substring( m[0].length );//移除匹配到的表达式如t为".a .b"那么匹配到.a后,t为" .b"
  }

posted on 2008-10-27 09:38 汪杰 阅读(795) 评论(0)  编辑 收藏 引用
只有注册用户登录后才能发表评论。

<2008年10月>
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

常用链接

留言簿(15)

随笔分类(1)

随笔档案(90)

文章分类(727)

文章档案(712)

相册

收藏夹

http://blog.csdn.net/prodigynonsense

友情链接

最新随笔

搜索

  •  

积分与排名

  • 积分 - 468988
  • 排名 - 6

最新随笔

最新评论

阅读排行榜

评论排行榜