;(function( window ){ var arr = []; var push = arr.push; var slice = arr.slice; var select ; var Expr; // 标识 var expando = "sizzle" + 1 * new Date(); // http://www.w3.org/TR/css3-selectors/#whitespace // 各种空白待穿正则字符串 var whitespace = "[\\x20\\t\\r\\n\\f]"; // 带空格选择器正则,记忆无空格选择器 // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier var identifier = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+"; var pseudos = ":(" + identifier + ")(?:\\((" + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: // 1. quoted (capture 3; capture 4 or capture 5) "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + // 2. simple (capture 6) "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + // 3. anything else (capture 2) ".*" + ")\\)|)"; // 属性选择器: http://www.w3.org/TR/selectors/#attribute-selectors var attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + // Operator (capture 2) "*([*^$|!~]?=)" + whitespace + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + "*\\]"; var rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ); // 快速选择器正则 ID 或者 TAG(包括*) 或者 CLASS 选择器 var rquickExpr = /^(?:#([\w-]+)|(\w+|\*)|\.([\w-]+))$/; // 连接符号 var rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ); // 层级符号正则'>',' ','+','~' var rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ); var matchExpr = { "ID": new RegExp( "^#(" + identifier + ")" ), "CLASS": new RegExp( "^\\.(" + identifier + ")" ), "TAG": new RegExp( "^(" + identifier + "|[*])" ), "PSEUDO": new RegExp( "^" + pseudos ), "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) }; var rheader = /^h\d$/i; // 浏览器代码正则 var rnative = /^[^{]+\{\s*\[native \w/; // token缓存 var tokenCache = createCache(); // 编译缓存 var compilerCache = createCache(); // 入口 function Sizzle( selector, context, results){ // 清除空格 selector = selector.replace( rtrim, "$1" ) var results = results || []; var match; var matcher; var elem; var m; var context = context || document; // 是否为最简选择器 if( match = rquickExpr.exec( selector )){ // Sizzle('#ID) if ( (m = match[1]) ) { elem = context.getElementById( m ); if( elem ){ results.push( elem ); } return results; // Sizzle("TAG") }else if( (m = match[2]) ){ push.apply( results, context.getElementsByTagName( selector ) ); return results; // Sizzle(".CLASS") }else if( (m = match[3]) ){ // 支持getElementsByClassName if( support.getElementsByClassName ){ push.apply( results, context.getElementsByClassName( m ) ); return results; } } } // 复杂选择调到select return select( selector, context, results); } // 创建缓存函数 function createCache() { var keys = []; function cache( key, value ) { // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) if ( keys.push( key + " " ) > 10 ) { // Only keep the most recent entries delete cache[ keys.shift() ]; } return (cache[ key + " " ] = value); } return cache; } // 函数标记函数 function markFunction( fn ) { fn[ expando ] = true; return fn; } // 错误函数 Sizzle.error = function( msg ) { throw new Error( "Syntax error, unrecognized expression: " + msg ); }; // 版本支持变量的对外访问入口 var support = Sizzle.support = {}; // 判断是否支持getElementsByClassName // 支持: IE<9 support.getElementsByClassName = rnative.test( document.getElementsByClassName ); // 表达式对象 // 存放各类相对位置,各种查询函数,各种过滤函数等。 Expr = { relative: { ">": { dir: "parentNode", first: true }, " ": { dir: "parentNode" }, "+": { dir: "previousSibling", first: true }, "~": { dir: "previousSibling" } }, filter: { "TAG": function( nodeNameSelector ) { var nodeName = nodeNameSelector.toLowerCase(); return nodeNameSelector === "*" ? function() { return true; } : function( elem ) { return elem.nodeName.toLowerCase() === nodeName; }; }, "CLASS": function( className ) { var className = className.toLowerCase(); return function( elem ) { return elem.className.toLowerCase() === className; }; }, "PSEUDO": function( pseudo, argument ) { var fn = Expr.pseudos[ pseudo ]; if ( fn[ expando ] ) { return fn( argument ); } return fn; } }, find: { "TAG": function( tag, context ) { return context.getElementsByTagName( tag ); }, "CLASS": support.getElementsByClassName&&function( tag, context ) { return context.getElementsByClassName( tag ); }, }, // 筛选方法 pseudos: { // not是个难点 // superMatcher将结果存入restlts,未匹配的元素则返回 // not两个路线一个是处理not参数中为复杂伪类筛选setMatcher // 一个是elementMatcher "not": markFunction(function( selector ){ var results = []; var input = []; var matcher = compile( selector ); return matcher[ expando ] ? markFunction(function( seed, matches, context){ var elem; var unmatched = matcher(seed, null, [] ); var i = seed.length; while ( i-- ) { if ( (elem = unmatched[i]) ) { seed[i] = !(matches[i] = elem); } } }): function( elem, context ) { input[0] = elem; matcher( input, null, results ); return !results.pop(); } } ), "target": function( elem ) { var hash = window.location && window.location.hash; return hash && hash.slice( 1 ) === elem.id; }, "header": function( elem ) { return rheader.test( elem.nodeName ); }, "root": function( elem ) { return elem === document.documentElement; }, // 以下为位置筛选,我们采用一个函数,但其index不同。 // 用createPositionalPseudo生成一个新函数,这个函数的index数组根据位置不同而不同 "first": createPositionalPseudo( function(){ return [0]; } ), "last":createPositionalPseudo( function( matchesIndex ,length){ return [ length-1 ]; } ), "eq": createPositionalPseudo( function( matchesIndex ,length, argument){ return [ argument < 0 ? argument + length : argument ]; } ), "even": createPositionalPseudo( function( matchesIndex, length ){ for(var i = 0; i<length; i+=2){ matchesIndex.push(i); } return matchesIndex; } ), "odd": createPositionalPseudo( function( matchesIndex, length ){ for(var i = 1; i<length; i+=2){ matchesIndex.push(i); } return matchesIndex; } ), "lt": createPositionalPseudo( function( matchesIndex ,length, argument){ var i = argument < 0 ? argument + length : argument; while(i--){ matchesIndex.push(i); } return matchesIndex; } ), "gt": createPositionalPseudo( function( matchesIndex, length, argument){ var i = argument < 0 ? argument + length : argument; while( ++i < length){ matchesIndex.push(i); } return matchesIndex; } ), } } // 返回一个函数,用于所有位置筛选 function createPositionalPseudo( fn ) { return markFunction( function( argument ){ argument = + argument; return markFunction(function( seed, matches ) { var j; var matchIndexes = fn([],seed.length,argument); var i = matchIndexes.length; while(i--){ if ( seed[ (j = matchIndexes[i]) ] ) { seed[j] = !(matches[j] = seed[j]); } } }) }) } // tokenize函数 // 将选择器字符串转化为方便使用的数组对象形式 tokenize = Sizzle.tokenize = function( selector, parseOnly ) { var cached = tokenCache[ selector + " " ]; // cached.slice生成新的数组,对其修改不会修改其引用缓存 if ( cached ) { return cached.slice( 0 ); } // 循环条件 var soFar = selector; // 结果数组 var groups = []; // 匹配参数 var matched; // 一个独立的tokens var tokens; // 辅助变量 var match; while ( soFar ) { //首次默认创建一个tokens //之后每碰到一个逗号新增一个新的tokens if ( !matched || (match = rcomma.exec( soFar )) ) { if ( match ) { // Don't consume trailing commas as valid soFar = soFar.slice( match[0].length ) || soFar; } groups.push( (tokens = []) ); } matched = false; // 关系token if ( (match = rcombinators.exec( soFar )) ) { matched = match.shift(); tokens.push({ value: matched, // Cast descendant combinators to space type: match[0].replace( rtrim, " " ) }); soFar = soFar.slice( matched.length ); } // TAG,CLASS,ID token for ( type in Expr.filter ) { if ((match = matchExpr[ type ].exec( soFar )) ) { matched = match.shift(); tokens.push({ value: matched, type: type, matches: match }); soFar = soFar.slice( matched.length ); } } // 一次循环到这里三个条件都不符合没有匹配结果时,跳出。 if ( !matched ) { break; } } // 意外跳出,soFar存在,报错。 return soFar ? Sizzle.error( selector ) : // 缓存后转成新数组返回(预防修改缓存内容) tokenCache( selector, groups ).slice( 0 ); }; // 将tokens转化为selector字符串形式。 function toSelector( tokens ) { var i = 0, len = tokens.length, selector = ""; for ( ; i < len; i++ ) { selector += tokens[i].value; } return selector; } // 压缩数组 // condense([undefined,1,2,3]) = [123]; function condense(matcherOut) { var newMatcherOut = []; var elem; for(var i =0; i< matcherOut.length;i++){ if((elem = matcherOut[i])){ newMatcherOut.push(elem); } } return newMatcherOut; } // 对多重上下文执行元素选择 // 用于上下文是数组的情况 // 服务于setMatcher返回函数的某些情况 function multipleContexts(selector,context,results){ for(var i = 0;i<context.length;i++){ Sizzle(selector, context[i],results); } return results; } // setMatcher筛选 // setMatcher是不同于elementMatcher的另一个方向,用来处理各种伪类筛选 function setMatcher( preFilter, selector, matcher, postFinder, postSelector){ if ( postFinder && !postFinder[ expando ] ) { postFinder = setMatcher( postFinder, postSelector ); } return markFunction(function( seed, results, context ) { var elems = seed || multipleContexts( selector || "*" , context.nodeType ? [ context ] : context ,[]); var matcherIn = elems; var matcherOut = []; if ( matcher ) { matcher( matcherIn, matcherOut); } matcherOut = condense(matcherOut); if ( postFinder ) { postFinder( null, results, matcherOut ); } else { push.apply( results, matcherOut ); } }) } // !addCombinator // 增加关系处理函数 // 返回关系函数,主要功能是,遍历种子节点的关系节点。 // 比如li>a,传入无数个种子节点a,a.parentNode,再执行matcher,matcher里再判断这个父亲节点是不是li function addCombinator( matcher, combinator ) { var dir = combinator.dir; return combinator.first ? function( elem, context ) { while( (elem = elem[ dir ]) ){ if ( elem.nodeType === 1 ) { return matcher( elem, context ); } } }: function( elem, context ) { while ( (elem = elem[ dir ]) ) { if ( elem.nodeType === 1 ) { if(matcher( elem, context )) { return true; } } } return false; } } // !elementMatcher // 生成matchers遍历器 // matchers数组存放我要过滤的函数,这个函数遍历所有过滤函数,一个不符合就返回false。 function elementMatcher( matchers ) { return function( elem, context ) { var i = matchers.length; while ( i-- ) { if ( !matchers[i]( elem, context ) ) { return false; } } return true; }; } // !matcherFromTokens // 根据tokens,生成过滤一组函数matchers,供elementMatcher使用 // 返回的是一个执行所有过滤函数的函数 function matcherFromTokens( tokens ){ var matchers = []; var matcher; var type; var i = 0; var j ; var len = tokens.length; for ( ; i < len; i++ ) { if ( (matcher = Expr.relative[ tokens[i].type ]) ) { matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; } else { matcher = Expr.filter[ (type = tokens[i].type) ].apply( null, tokens[i].matches ); if ( matcher[ expando ] ) { j = i+1; return setMatcher( i > 0 && elementMatcher( matchers ), i > 0 && toSelector( tokens.slice( 0, i ) ), matcher, j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), j < len && toSelector( tokens ) ); } matchers.push( matcher ); } } return elementMatcher( matchers ); } // !matcherFromGroupMatchers // 返回超级匹配器, function matcherFromGroupMatchers( elementMatchers, setMatchers ){ var bySet = setMatchers.length > 0, byElement = elementMatchers.length > 0; // !!最重要superMatcher,也是最核心的函数,其它的函数为它服务。 // 获取种子元素,遍历所有种子元素。 // 遍历elementMatchers // 符合的推入结果数组 // 一个选择器(逗号隔开的)生成一个elementMatcher,elementMatchers是存放所有elementMatcher的数组 var superMatcher = function( seed, context, results) { var elems = seed || Expr.find["TAG"]( "*", document ); var len = elems.length var i = 0; var j; var unmatched = seed ? slice.call(seed, 0) : undefined ; var setMatched = []; for ( ; i !== len && (elem = elems[i]) != null; i++ ) { if( byElement ){ j = 0; while ( (matcher = elementMatchers[j++]) ) { if ( matcher( elem, context) ) { results.push( elem ); break; } } } } if ( bySet) { j = 0; while ( (matcher = setMatchers[j++]) ) { matcher( unmatched, setMatched, context); } push.apply( results, setMatched ); } return unmatched; } return bySet ? markFunction( superMatcher ) : superMatcher;; } // compile // 最初的编译器,存放elementMatchers,缓存超级匹配函数并返回 compile = Sizzle.compile = function( selector, match ) { var i; var elementMatchers = []; var setMatchers = []; var cached = compilerCache[ selector + " "]; if ( !cached ) { if ( !match ) { match = tokenize( selector ); } i = match.length; while ( i-- ) { cached = matcherFromTokens( match[i] ); if ( cached[ expando ] ) { setMatchers.push( cached ); } else { elementMatchers.push( cached ); } } cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers )); } return cached; } // select // 兼容的自写的选择器 select = Sizzle.select = function( selector, context, results){ var token; var seed; var tokens; var find; var match = tokenize( selector ) if ( match.length === 1 ) { // tokens var tokens = match[0].slice( 0 ); // 如果tokens的首项是ID,将其设置为上下文 if ( (token = tokens[0]).type === 'ID' ){ context = document.getElementById(token.matches[0]); selector = selector.slice( tokens.shift().value.length ); } // 生成种子seed // 如"div ul li",所谓种子就是所有的li // 后面编译函数需要过滤出符合祖先是ul,ul的祖先是div的节点 // 在筛选选择中,如li:eq(0),不可以从左边直接取种子。 i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;; while ( i-- ){ token = tokens[i]; if ( Expr.relative[ (type = token.type) ] ) { break; } if((find = Expr.find[ type ])) if( seed = find( token.matches[0],context ) ) { tokens.splice( i, 1 ); selector = toSelector( tokens ) break; } } }; // 根据selector,tokens(match防止对原tokens修改)生成superMatcher并调用 compile( selector, match )( seed, context, results ); return results; } // 对外入口 window.MSizzle = Sizzle; })(window) // 测试/* console.log(MSizzle("a:not(.b)")) console.log(Sizzle("a:not(.b)"))
1.整体的思路是,comple生成超级选择函数,这个函数主要用两种情况,一种是以前的elementMatcher,一种是setMatcher,用函数expando属性来区别执行哪条。本章的内容主要分析伪类筛选的基本筛选,大多数都是setMatcher路线,当然少数如:header,:root,:target则不是。
我们继续以一条路径来分析setMatcher路线,div:first,在setMatcher函数里,先根据前面的选择器执行Sizzle(’div‘),在这些div里进行基本筛选的first筛选。
2.markFunction,对函数进行标记并返回函数。Sizzle中根据选择器获取函数,如果有标记属性,则存入setMatchers。这是伪类路线,否则存入elementMatchers,一般路线。示例:
1 var expando = "sizzle" + 1 * new Date(); 2 var filter = { 3 'pseudos': markFunction(function(){ 4 5 }), 6 'TAG': function(){ 7 8 } 9 } 10 function markFunction(fn){ 11 fn[expando] = true; 12 return fn; 13 } 14 function devider(selectorType){ 15 if( filter[type][expando] ){ 16 console.log('伪类路线') 17 }else{ 18 console.log('基本路线') 19 } 20 } 21 devider('pseudos')
3.只要选择器中有走setMatchers路线的方法