1、sizzle在document.querySelectorAll可以使用情况下,如果context是document优先使用querySelectorAll查询
Sizzle = function(query, context, extra, seed){ context = context || document; if ( !seed && context.nodeType === 9 && !Sizzle.isXML(context) ) { try { return makeArray( context.querySelectorAll(query), extra ); } catch(e){} } return oldSizzle(query, context, extra, seed); };
2、否则根据正则,拆分选择器,存入parts
do { // chunker的lastIndex归0 chunker.exec(""); m = chunker.exec(soFar); if ( m ) { //每次重新赋值匹配右半部分 soFar = m[3]; //从左依次存入数组 parts.push( m[1] ); //当有“,”时,代表并列关系,额外标示,退出循环 if ( m[2] ) { extra = m[3]; break; } } } while ( m );
3.1、parts长度大于1且匹配POS正则的选择器,进人下面分支。
POS的正则(/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/)
为了方便理解举个例子,例如“p:first + span:first”
//sizzle多次调用时,结合当前的context快速定位,条件是“+”、“>”、“”、“~”中一个 //拿例子来说,再次sizzle,到此就是直接调用posProcess函数,选择器是+span:first,而context是已经找到的[p] if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { set = posProcess( parts[0] + parts[1], context ); } else { //拿例子说就是先根据context,查找p:first set = Expr.relative[ parts[0] ] ? [ context ] : Sizzle( parts.shift(), context ); //拿例子说就是依次去处理后面的+span:first while ( parts.length ) { selector = parts.shift(); if ( Expr.relative[ selector ] ) { selector += parts.shift(); } set = posProcess( selector, set ); } }
下面来看看posProcess函数
var posProcess = function(selector, context){ var tmpSet = [], later = "", match, root = context.nodeType ? [context] : context; // 拿例子说,先把:first之类替换掉,找当前context下的span,存入tmpSet //同时把:first之类的存入later保存 while ( (match = Expr.match.PSEUDO.exec( selector )) ) { later += match[0]; selector = selector.replace( Expr.match.PSEUDO, "" ); } selector = Expr.relative[selector] ? selector + "*" : selector; for ( var i = 0, l = root.length; i < l; i++ ) { Sizzle( selector, root[i], tmpSet ); } return Sizzle.filter( later, tmpSet ); };
把剩下判断交由Sizzle.filter去验证,最后给出结果,filter比较长,就不贴了,直接看源码吧。
3.2看看另一个分支。
先是一个优先匹配的原则,找到后更新当前的context
if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { ret = Sizzle.find( parts.shift(), context, contextXML ); context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; }
继续
if ( context ) { //在此可以看出Sizzle是从右到左的寻找 ret = seed ? { expr: parts.pop(), set: makeArray(seed) } : Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); //找出匹配的集合 set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; if ( parts.length > 0 ) { checkSet = makeArray(set); } else { prune = false; } //依次遍历匹配 while ( parts.length ) { cur = parts.pop(); pop = cur; if ( !Expr.relative[ cur ] ) { cur = ""; } else { pop = parts.pop(); } if ( pop == null ) { pop = context; } Expr.relative[ cur ]( checkSet, pop, contextXML ); } } else { checkSet = parts = []; }
有些情况不准,需求再过滤次
if ( toString.call(checkSet) === "[object Array]" ) { if ( !prune ) { results.push.apply( results, checkSet ); } //context存在时,存在cotext和parentNode混判情况,需要再判断次 else if ( context && context.nodeType === 1 ) { for ( i = 0; checkSet[i] != null; i++ ) { if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { results.push( set[i] ); } } } else { for ( i = 0; checkSet[i] != null; i++ ) { if ( checkSet[i] && checkSet[i].nodeType === 1 ) { results.push( set[i] ); } } } } else { makeArray( checkSet, results ); }
处理并列关系的选择器,要排重
if ( extra ) { Sizzle( extra, origContext, results, seed ); Sizzle.uniqueSort( results ); }