JQuery日记_5.14 Sizzle选择器(七)

上篇说道,tokenize方法会把selector分割成一个个selector逻辑单元(如div>a是三个逻辑单元 ‘div‘,‘>‘,‘a‘)并为之片段赋予对应类型的过滤函数。

for ( type in Expr.filter ) {
               if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
                    (match = preFilters[ type ]( match ))) ) {
                    matched = match.shift();
                    tokens.push({
                         value: matched,
                         type: type,
                         matches: match
                    });
                    soFar = soFar.slice( matched.length );
               }
 }

然后选出最后selector逻辑单元(是指由需要上下文的选择器,如id,tag,class等)所对应的元素集作为从右向左(一般情况)过滤的候选元素集,match(正则捕获组)是selector逻辑片段的解析结果(如[arr="111"]根据正则解析为arr,",=,111 ),在selector逻辑片段是ATTR、CHILD、PSEUDO是需要调用preFilter对match进行修正.

preFilter: {
             //match是捕获组
             //假设:[arr^=‘val‘]
             "ATTR": function( match ) {
                   //attr的第一个捕获 组是arr,将其中的转码变成原来的字符
                  match[1] = match[1].replace( runescape, funescape );

                   // Move the given value to match[3] whether quoted or unquoted
                   // 将val放到捕获组3里,原来的捕获组3捕获‘或"
                  match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape );
                   //如果捕获组2是~=,在match[3]前后加空格,以方便匹配单个单词
                   if ( match[2] === "~=" ) {
                        match[3] = " " + match[3] + " ";
                  }
                   //match[0] = ‘[arr^=‘val‘]‘
                   //match[1] = ‘arr‘
                   //match[2] = ‘=‘
                   //match[3] = ‘111‘
                   return match.slice( 0, 4 );
            },

             "CHILD": function( match ) {
                   /*  例如nth-child(-2n+1)的捕获组
                        mathc[1] nth
                        mathc[2] child
                        mathc[3] 2n+1
                        mathc[4] 2n
                        mathc[5] -
                        mathc[6] 2
                        mathc[7] +
                        mathc[8] 1
                  */
                  match[1] = match[1].toLowerCase();
                   // nth必须需要参数
                   if ( match[1].slice( 0, 3 ) === "nth" ) {
                         // nth-* requires argument
                         if ( !match[3] ) {
                              Sizzle.error( match[0] );
                        }

                         // numeric x and y parameters for Expr.filter.CHILD
                         // remember that false/true cast respectively to 0/1
                         // xn + y
                         // 将even,odd修正为xn+y,match[4]修正为+-x
                        match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
                         // 将match[5]替换为+-y
                        match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );

                   // other types prohibit arguments
                   // 除nth外其他类型禁止参数
                  } else if ( match[3] ) {
                        Sizzle.error( match[0] );
                  }
                   // match[0] :nth-child(-2n+1)
                   // match[1] nth
                   // match[2] child
                   // match[3] -2n+1
                   // match[4] -2
                   // match[5] 1
                   // match[6] 2
                   // match[7] +
                   // match[8] 1
                   return match;
            },
             /**
             * match[1] :后伪类类型
             * match[2] 伪类参数
             * match[3] 参数中的‘或者"
             * match[4] 除去‘或"的伪类
             */
             "PSEUDO": function( match ) {
                   var excess,
                        unquoted = !match[5] && match[2];

                   //是CHILD伪类,返回null
                   if ( matchExpr[ "CHILD"].test( match[0] ) ) {
                         return null;
                  }

                   // Accept quoted arguments as-is
                   // 参数有引号
                   //将match[2]替换为无引号的match[4]参数
                   if ( match[3] && match[4] !== undefined ) {
                        match[2] = match[4];

                   // Strip excess characters from unquoted arguments
                   // 除去带引号的参数的多余字符
                  } else if ( unquoted && rpseudo.test( unquoted ) &&
                         // Get excess from tokenize (recursively)
                         //excess多余字符的长度
                        (excess = tokenize( unquoted, true )) &&
                         //excess多余参数的索引位置,excess是个负值,以便截取到多余字符之前
                        (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {

                         // excess is a negative index
                        match[0] = match[0].slice( 0, excess );
                        match[2] = unquoted.slice( 0, excess );
                  }

                   // Return only captures needed by the pseudo filter method (type and argument)
                   return match.slice( 0, 3 );
            }
      }

JQuery日记_5.14 Sizzle选择器(七),布布扣,bubuko.com

时间: 2024-10-12 14:11:37

JQuery日记_5.14 Sizzle选择器(七)的相关文章

JQuery日记_5.13 Sizzle选择器(六)选择器的效率

当选择表达式不符合快速匹配(id,tag,class)和原生QSA不可用或返回错误时,将调用select(selector, context, results, seed)方法,此方法迭代DOM选择.过滤元素, 在DOM树非常大的时候为了保证效率,应该保证html设计的合理,尽量使用可快速匹配(id,tag,class)的表达式,其次是QSA支持的选择器,尽量不要使用jquery扩展的selector和嵌套selector,然后是尽量不要使用位置伪类(它是从左向右查找,需要多次循环内套循环遍历)

JQuery日记 5.11 Sizzle选择器(五)

//设置当前document和document对应的变量和方法 setDocument = Sizzle.setDocument = function( node ) { var hasCompare, //node为Element时返回node所属document //node为Document时返回node //node为空时返回window.document doc = node ? node.ownerDocument || node : preferredDoc, //document

JQuery_2.1.0_日记 5.5 Sizzle选择器(三)

function Sizzle( selector, context, results, seed ) { var match, elem, m, nodeType, // QSA vars i, groups, old, nid, newContext, newSelector; if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { setDocument( context );

JQuery_2.1.0_日记 5.4 Sizzle选择器(二)

(1) whitespace = "[\\x20\\t\\r\\n\\f]"; 匹配css3中空白符. \x20:空格;\t水平制表符(tab);\r\n回车换行\f换页符 (2) characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+" 匹配\后任意字符,字母或数字或-,ascii值非\00-\xa0范围内的字符 (3) identifier = characterEncoding.replace( "

JQuery_2.1.0_日记 5.4 Sizzle选择器(一) 正则中那些\\\\和\\

Sizzle中恐怖的正则. 字面量的正则也许还好理解,那么由字符串编译而成的正则呢. \\和\\\\ 由字符'\\\\'编译而成的正则是/\\/,第一个\转义第两个\,所以其匹配一个\字符(这个\字符是代表字符本身) Test_Script var s = '\\' ; alert(s); // '\' var rs = '\\\\' ; var matches = s.match(new RegExp(rs)); alert(matches[0]) // '\' 由字符串'\\3'编译而成的正

JQuery_2.1.0_日记 5.8 Sizzle选择器(四)

Sizzle( selector, context, results, seed )的关键步骤 1,传入的context对应的context和当前document是否一致,不一致调用setDocument()重新设置document,用于frame的情况. 2,如果context为空修正context为document 3,selector如果不是字符串或者context不是Element或Document直接返回空数组. 4,如果文档是HTML并且未传入过滤结果集seed,尝试用原生方法get

JQuery日期_5.20 JQuery对Sizzle选择器的扩展

代码很简单直接上源码 function winnow( elements, qualifier, not ) { //如果qualifier是函数 if ( jQuery.isFunction( qualifier ) ) { //not为true时,返回qualifier返回false的elements //not为false时,返回qualifier返回true的elements return jQuery.grep( elements, function( elem, i ) { /* j

JQuery日记 6.3 JQuery遍历模块

jQuery.extend({ // 返回elem延DOM树某个方向访问的所有节点,直到遇到until条件 dir: function( elem, dir, until ) { var matched = [], truncate = until !== undefined; while ( (elem = elem[ dir ]) && elem.nodeType !== 9 ) { if ( elem.nodeType === 1 ) { if ( truncate &&am

jQuery-1.9.1源码分析系列(三) Sizzle选择器引擎——编译原理

这一节要分析的东东比较复杂,篇幅会比较大,也不知道我描述后能不能让人看明白.这部分的源码我第一次看的时候也比较吃力,现在重头看一遍,再分析一遍,看能否查缺补漏. 看这一部分的源码需要有一个完整的概念后去看才比较容易看懂,所以我们先把整个编译的原理阐述以后再进行解析. 还是以上次的那个CSS选择器为例:#chua > a + .group labe[for="age"].按照我们正常解析CSS的思路从右往左解析,解析之前词法分析完毕,词法分析结果保存在tokens中. 正常的思路: