最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Sizzle源码分析(四) Sizzle静态方法分析

    正文概述 掘金(周龙龙)   2021-05-30   736

    简介

    Sizzle 的静态方法起了辅助的作用,帮助完成一些对元素属性获取或者转义一些选择器,完成一些对元素节点的排序等等。我会对这些方法进行一个注释与讲解,等把所有的这些辅助方法讲完后,会对sizzle的是怎么样选择到元素的一个流程,还有架构做一个梳理。解读方法的顺序基本是按照代码的先后顺序来讲。如果有误,请大家纠正。

    matches

    对已有元素进行筛选

    /**
     * [matches] 对已有元素进行筛选
     * @param  {[type]} expr    
     * @param  {[type]} elements
     * @return Sizzle elements
     */
    Sizzle.matches = function(expr, elements) {
         //selector, context, results, seed,这个就是种子元素中来过滤查找元素,不用在上下文中重新来查找
         return Sizzle(expr, null, null, elements);
    };
    

    Sizzle.matchesSelector

    查看当前元素含有的是否包含这个选择器

    /**
     * [matchesSelector ] 查看当前元素含有的是否包含这个选择
     * @param  {[element]} elem 
     * @param  {[string]} expr 
     * @return {[boolean]}    true or false
     */
    Sizzle.matchesSelector = function(elem, expr) {
            // 设置当前的上下文的兼容性
            setDocument(elem);
            /**
             * support.matchesSelector 是否支持
             * documentIsHTML 是不是html
             * !nonnativeSelectorCache[expr + " "]  查看是否在缓存中为false
             * rbuggyMatches 不存在或!rbuggyMatches.test(expr) matches不存在bug
             * rbuggyQSA不存在或 就是QSA不存在bug 
             */
            if (support.matchesSelector && documentIsHTML &&
                    !nonnativeSelectorCache[expr + " "] &&
                    (!rbuggyMatches || !rbuggyMatches.test(expr)) &&
                    (!rbuggyQSA || !rbuggyQSA.test(expr))) {
    
                    try {
                            // 看是否能匹配上
                            var ret = matches.call(elem, expr);
                            // 如果选择器与元素匹配上 或者不是文档片段或者还在当前或者还在当前上下文
                            // IE 9's matchesSelector returns false on disconnected nodes
                            if (ret || support.disconnectedMatch ||
    
                                    // As well, disconnected nodes are said to be in a document
                                    // fragment in IE 9
                                    elem.document && elem.document.nodeType !== 11) {
                                    // 直接返回true
                                    return ret;
                            }
                    } catch (e) {
                            // 如果不能支持选择器放入 nonnativeSelectorCache
                            nonnativeSelectorCache(expr, true);
                    }
            }
            // 走入catch就会走这里,重新进行元素的一个匹配,如果找道返回true
            return Sizzle(expr, document, null, [elem]).length > 0;
    };
    
    

    Sizzle.contains

    来表示传入的节点是否为该节点的后代节点,返回true or false

    /**
     * [contains]
     * @param  {[element]} context
     * @param  {[element]} elem   
     * @return {[boolean]}        
     */
    Sizzle.contains = function(context, elem) {
    
            // Set document vars if needed
            // Support: IE 11+, Edge 17 - 18+
            // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
            // two documents; shallow comparisons work.
            // eslint-disable-next-line eqeqeq
            // 根据文档来设置上下问
            if ((context.ownerDocument || context) != document) {
                    setDocument(context);
            }
            // 来表示传入的节点是否为该节点的后代节点,返回true or false
            return contains(context, elem);
    };
    

    Sizzle.escape

    转义css选择器,首先把选择器转为字符串,然后用正则匹配需要转义的字符串,替换成unicode字符。这两个方法我已经在前置内容中已经讲过了。大家没看的可以从前几篇文章中找一下呢

    Sizzle.escape = function(sel) {
            return (sel + "").replace(rcssescape, fcssescape);
    };
    
    

    Sizzle.error

    传参返回一个错误提示

    
    Sizzle.error = function(msg) {
            throw new Error("Syntax error, unrecognized expression: " + msg);
    };
    
    

    Sizzle.uniqueSort

    这个方法主要做的是给文档排序,上次节代码里面我已经讲到了怎么给文档排序了,不了的可以查看一下。还有一个做用就是删除重复的文档。我记得上节也讲到了sortOrder 这个方法了,如果a === b 相等时候 hasDuplicate 为true,说明文档有重复或者元素重复。

    // Support: Chrome 14-35+ // Always assume duplicates if they aren't passed to the comparison function 加入没有传递这个参数就是一只重复着 support.detectDuplicates = !!hasDuplicate; 其实就是转了个boolean类型。这行代码在jquery的2921行。

    // One-time assignments

    // Sort stability 这个代码是对排序稳定性的一个测试, expando 是sizzle + 一个时间戳。 sortOrder = function( a, b ) { if ( a === b ) { hasDuplicate = true; } return 0; } // 就这块return 0 expando还是原来的顺序 hasDuplicate = true; support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando;

    /**
     * Document sorting and removing duplicates
     * @param {ArrayLike} results
     */
    Sizzle.uniqueSort = function(results) {
            var elem,
                    duplicates = [],
                    j = 0,
                    i = 0;
    
            // Unless we *know* we can detect duplicates, assume their presence
            // Document的时候回执行sortOrder方法,如果支持hasCompare? hasDuplicate是true,否则是false
            hasDuplicate = !support.detectDuplicates;
            //sizzle1622222893304 就是false,&& results.slice(0) 把result 返回一个新数组浅拷贝
            sortInput = !support.sortStable && results.slice(0);
            然后对results进行排序
            results.sort(sortOrder);
            if (hasDuplicate) {
                    while ((elem = results[i++])) {
                            if (elem === results[i]) {
                                    j = duplicates.push(i);
                            }
                    }
                    // j 等于duplicates.length 存储的就是数字,duplicates存储的是重复的数字的位置
                    while (j--) {
                            results.splice(duplicates[j], 1);
                    }
            }
    
            // Clear input after sorting to release objects
            // See https://github.com/jquery/sizzle/pull/225
            sortInput = null;
            返回删剩下没有重复的元素
            return results;
    };
    

    Sizzle.getText

    获取元素或者一组元素的文本内容

    /**
     * Utility function for retrieving the text value of an array of DOM nodes
     * @param {Array|Element} elem
     */
     、、
    getText = Sizzle.getText = function( elem ) {
    	var node,
    		ret = "",
    		i = 0,
    		nodeType = elem.nodeType;
            // 如果不存在nodeType属性,说明是类数组
    	if ( !nodeType ) {
    
    		// If no nodeType, this is expected to be an array
    		while ( ( node = elem[ i++ ] ) ) {
                            // 递归拿到元素的内容
    			// Do not traverse comment nodes
    			ret += getText( node );
    		}
                    // 如果是元素或者document 或者 文档片段
    	} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
    
    		// Use textContent for elements
    		// innerText usage removed for consistency of new lines (jQuery #11153)
                    // 返回元素中文本内容
    		if ( typeof elem.textContent === "string" ) {
    			return elem.textContent;
    		} else {
                            否则遍历递归每个兄弟节点拿到文本
    			// Traverse its children
    			for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
    				ret += getText( elem );
    			}
    		}
                    // 若果是CDATA节点或者文本节点 ,返回nodevalue
    	} else if ( nodeType === 3 || nodeType === 4 ) {
    		return elem.nodeValue;
    	}
    
    	// Do not include comment or processing instruction nodes
    
    	return ret;
    };
    

    Sizzle.selectors

    这个方法主要是绑定了 cacheLength、createPseudo、match、attrHandle、find、preFilter、filter、pseudos这个几个方法。

    cacheLength 这个属性的作用是 方法createCache 的中keys的长度,如果超过keys的长度超过了50,让第一个缓存出队。

    createPseudo:markFunction 这个方法默认是接收一个fn参数,给fn添加一个[expando] = true的属性。并返回这个fn。

    matchExpr这个属性这个在分析一之时,我分析过了所以的属性,用来匹配各种选择器。 attrHandle: 空对象 Expr.attrHandle[arr[i]] = handler;

    find: 空对象,在setDocument初始化的的时候赋予的对应的key:value,返回元素数组 不明白看看上一章

    relative: 选择的相对位置

    preFilter: 预过滤器

    filter:过滤器 在setDocument初始化的的时候赋予的对应的key:value,返回true or false

    pseudos:伪类选择器

    这块处理我会在下节继续接着解析css选择器,选中html元素结合着把这块来一个传插,并举一些实际的代码。 这块相对比较好理解,会举几个方法来讲一下。这块不理解可以先看,下章sizzle是怎么选择对这些选择器是如何处理的。

     Sizzle.selectors = {
    	// Can be adjusted by the user
    	cacheLength: 50,
    	createPseudo: markFunction,
    	match: matchExpr,
    
    	attrHandle: {},
    
    	find: {},
            //我们匹配选择器dir 这样处理 relative['dir'] ,通过这样来拿到这元素位置
    	relative: {
    		">": { dir: "parentNode", first: true },
    		" ": { dir: "parentNode" },
    		"+": { dir: "previousSibling", first: true },
    		"~": { dir: "previousSibling" }
    	},
            // 这块的preFilter做的处理,预先解析,生成的token做一个预判,
    	preFilter: {
    		"ATTR": function( match ) {
    			match[ 1 ] = match[ 1 ].replace( runescape, funescape );
    
    			// Move the given value to match[3] whether quoted or unquoted
    			match[ 3 ] = ( match[ 3 ] || match[ 4 ] ||
    				match[ 5 ] || "" ).replace( runescape, funescape );
    
    			if ( match[ 2 ] === "~=" ) {
    				match[ 3 ] = " " + match[ 3 ] + " ";
    			}
    
    			return match.slice( 0, 4 );
    		},
                     /*
                      match:  [0: ":nth-child(2)"
                        1: "nth"
                        2: "child"
                        3: "2"
                        4: 0
                        5: 2
                        6: undefined
                        7: ""
                        8: "2"
                        groups: undefined
                        index: 0
                        input: ":nth-child(2)"
                        length: 9]
                     */
    		"CHILD": function( match ) {
    			/* matches from matchExpr["CHILD"]
    				1 type (only|nth|...)
    				2 what (child|of-type)
    				3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
    				4 xn-component of xn+y argument ([+-]?\d*n|)
    				5 sign of xn-component
    				6 x of xn-component
    				7 sign of y-component
    				8 y of y-component
    			*/
                           // 拿到nth后代选择器
    			match[ 1 ] = match[ 1 ].toLowerCase();
                          //  如果是nth 
    			if ( match[ 1 ].slice( 0, 3 ) === "nth" ) {
                                    // 判断后端选择的nth-child(arg) arg是否有参数or 0
    				// 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
    				match[ 4 ] = +( match[ 4 ] ?
    					match[ 5 ] + ( match[ 6 ] || 1 ) :
    					2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) );
    				match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" );
                                     其他选择器报错
    				// other types prohibit arguments
    			} else if ( match[ 3 ] ) {
    				Sizzle.error( match[ 0 ] );
    			}
                             //返回组装后的租户在哪个结果
    			return match;
    		},
    
    		"PSEUDO": function( match ) {
    			var excess,
    				unquoted = !match[ 6 ] && match[ 2 ];
    
    			if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) {
    				return null;
    			}
    
    			// Accept quoted arguments as-is
    			if ( match[ 3 ] ) {
    				match[ 2 ] = match[ 4 ] || match[ 5 ] || "";
    
    			// Strip excess characters from unquoted arguments
    			} else if ( unquoted && rpseudo.test( unquoted ) &&
    
    				// Get excess from tokenize (recursively)
    				( excess = tokenize( unquoted, true ) ) &&
    
    				// advance to the next closing parenthesis
    				( 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 );
    		}
    	},
    
    	filter: {
    
    		"TAG": function( nodeNameSelector ) {
    			var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
    			return nodeNameSelector === "*" ?
    				function() {
    					return true;
    				} :
    				function( elem ) {
    					return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
    				};
    		},
    
    		"CLASS": function( className ) {
    			var pattern = classCache[ className + " " ];
    
    			return pattern ||
    				( pattern = new RegExp( "(^|" + whitespace +
    					")" + className + "(" + whitespace + "|$)" ) ) && classCache(
    						className, function( elem ) {
    							return pattern.test(
    								typeof elem.className === "string" && elem.className ||
    								typeof elem.getAttribute !== "undefined" &&
    									elem.getAttribute( "class" ) ||
    								""
    							);
    				} );
    		},
    
    		"ATTR": function( name, operator, check ) {
    			return function( elem ) {
    				var result = Sizzle.attr( elem, name );
    
    				if ( result == null ) {
    					return operator === "!=";
    				}
    				if ( !operator ) {
    					return true;
    				}
    
    				result += "";
    
    				/* eslint-disable max-len */
    
    				return operator === "=" ? result === check :
    					operator === "!=" ? result !== check :
    					operator === "^=" ? check && result.indexOf( check ) === 0 :
    					operator === "*=" ? check && result.indexOf( check ) > -1 :
    					operator === "$=" ? check && result.slice( -check.length ) === check :
    					operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 :
    					operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
    					false;
    				/* eslint-enable max-len */
    
    			};
    		},
    
    		"CHILD": function( type, what, _argument, first, last ) {
    			var simple = type.slice( 0, 3 ) !== "nth",
    				forward = type.slice( -4 ) !== "last",
    				ofType = what === "of-type";
    
    			return first === 1 && last === 0 ?
    
    				// Shortcut for :nth-*(n)
    				function( elem ) {
    					return !!elem.parentNode;
    				} :
    
    				function( elem, _context, xml ) {
    					var cache, uniqueCache, outerCache, node, nodeIndex, start,
    						dir = simple !== forward ? "nextSibling" : "previousSibling",
    						parent = elem.parentNode,
    						name = ofType && elem.nodeName.toLowerCase(),
    						useCache = !xml && !ofType,
    						diff = false;
    
    					if ( parent ) {
    
    						// :(first|last|only)-(child|of-type)
    						if ( simple ) {
    							while ( dir ) {
    								node = elem;
    								while ( ( node = node[ dir ] ) ) {
    									if ( ofType ?
    										node.nodeName.toLowerCase() === name :
    										node.nodeType === 1 ) {
    
    										return false;
    									}
    								}
    
    								// Reverse direction for :only-* (if we haven't yet done so)
    								start = dir = type === "only" && !start && "nextSibling";
    							}
    							return true;
    						}
    
    						start = [ forward ? parent.firstChild : parent.lastChild ];
    
    						// non-xml :nth-child(...) stores cache data on `parent`
    						if ( forward && useCache ) {
    
    							// Seek `elem` from a previously-cached index
    
    							// ...in a gzip-friendly way
    							node = parent;
    							outerCache = node[ expando ] || ( node[ expando ] = {} );
    
    							// Support: IE <9 only
    							// Defend against cloned attroperties (jQuery gh-1709)
    							uniqueCache = outerCache[ node.uniqueID ] ||
    								( outerCache[ node.uniqueID ] = {} );
    
    							cache = uniqueCache[ type ] || [];
    							nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
    							diff = nodeIndex && cache[ 2 ];
    							node = nodeIndex && parent.childNodes[ nodeIndex ];
    
    							while ( ( node = ++nodeIndex && node && node[ dir ] ||
    
    								// Fallback to seeking `elem` from the start
    								( diff = nodeIndex = 0 ) || start.pop() ) ) {
    
    								// When found, cache indexes on `parent` and break
    								if ( node.nodeType === 1 && ++diff && node === elem ) {
    									uniqueCache[ type ] = [ dirruns, nodeIndex, diff ];
    									break;
    								}
    							}
    
    						} else {
    
    							// Use previously-cached element index if available
    							if ( useCache ) {
    
    								// ...in a gzip-friendly way
    								node = elem;
    								outerCache = node[ expando ] || ( node[ expando ] = {} );
    
    								// Support: IE <9 only
    								// Defend against cloned attroperties (jQuery gh-1709)
    								uniqueCache = outerCache[ node.uniqueID ] ||
    									( outerCache[ node.uniqueID ] = {} );
    
    								cache = uniqueCache[ type ] || [];
    								nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
    								diff = nodeIndex;
    							}
    
    							// xml :nth-child(...)
    							// or :nth-last-child(...) or :nth(-last)?-of-type(...)
    							if ( diff === false ) {
    
    								// Use the same loop as above to seek `elem` from the start
    								while ( ( node = ++nodeIndex && node && node[ dir ] ||
    									( diff = nodeIndex = 0 ) || start.pop() ) ) {
    
    									if ( ( ofType ?
    										node.nodeName.toLowerCase() === name :
    										node.nodeType === 1 ) &&
    										++diff ) {
    
    										// Cache the index of each encountered element
    										if ( useCache ) {
    											outerCache = node[ expando ] ||
    												( node[ expando ] = {} );
    
    											// Support: IE <9 only
    											// Defend against cloned attroperties (jQuery gh-1709)
    											uniqueCache = outerCache[ node.uniqueID ] ||
    												( outerCache[ node.uniqueID ] = {} );
    
    											uniqueCache[ type ] = [ dirruns, diff ];
    										}
    
    										if ( node === elem ) {
    											break;
    										}
    									}
    								}
    							}
    						}
    
    						// Incorporate the offset, then check against cycle size
    						diff -= last;
    						return diff === first || ( diff % first === 0 && diff / first >= 0 );
    					}
    				};
    		},
    
    		"PSEUDO": function( pseudo, argument ) {
    
    			// pseudo-class names are case-insensitive
    			// http://www.w3.org/TR/selectors/#pseudo-classes
    			// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
    			// Remember that setFilters inherits from pseudos
    			var args,
    				fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
    					Sizzle.error( "unsupported pseudo: " + pseudo );
    
    			// The user may use createPseudo to indicate that
    			// arguments are needed to create the filter function
    			// just as Sizzle does
    			if ( fn[ expando ] ) {
    				return fn( argument );
    			}
    
    			// But maintain support for old signatures
    			if ( fn.length > 1 ) {
    				args = [ pseudo, pseudo, "", argument ];
    				return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
    					markFunction( function( seed, matches ) {
    						var idx,
    							matched = fn( seed, argument ),
    							i = matched.length;
    						while ( i-- ) {
    							idx = indexOf( seed, matched[ i ] );
    							seed[ idx ] = !( matches[ idx ] = matched[ i ] );
    						}
    					} ) :
    					function( elem ) {
    						return fn( elem, 0, args );
    					};
    			}
    
    			return fn;
    		}
    	},
    
    	pseudos: {
    
    		// Potentially complex pseudos
    		"not": markFunction( function( selector ) {
    
    			// Trim the selector passed to compile
    			// to avoid treating leading and trailing
    			// spaces as combinators
    			var input = [],
    				results = [],
    				matcher = compile( selector.replace( rtrim, "$1" ) );
    
    			return matcher[ expando ] ?
    				markFunction( function( seed, matches, _context, xml ) {
    					var elem,
    						unmatched = matcher( seed, null, xml, [] ),
    						i = seed.length;
    
    					// Match elements unmatched by `matcher`
    					while ( i-- ) {
    						if ( ( elem = unmatched[ i ] ) ) {
    							seed[ i ] = !( matches[ i ] = elem );
    						}
    					}
    				} ) :
    				function( elem, _context, xml ) {
    					input[ 0 ] = elem;
    					matcher( input, null, xml, results );
    
    					// Don't keep the element (issue #299)
    					input[ 0 ] = null;
    					return !results.pop();
    				};
    		} ),
    
    		"has": markFunction( function( selector ) {
    			return function( elem ) {
    				return Sizzle( selector, elem ).length > 0;
    			};
    		} ),
    
    		"contains": markFunction( function( text ) {
    			text = text.replace( runescape, funescape );
    			return function( elem ) {
    				return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1;
    			};
    		} ),
    
    		// "Whether an element is represented by a :lang() selector
    		// is based solely on the element's language value
    		// being equal to the identifier C,
    		// or beginning with the identifier C immediately followed by "-".
    		// The matching of C against the element's language value is performed case-insensitively.
    		// The identifier C does not have to be a valid language name."
    		// http://www.w3.org/TR/selectors/#lang-pseudo
    		"lang": markFunction( function( lang ) {
    
    			// lang value must be a valid identifier
    			if ( !ridentifier.test( lang || "" ) ) {
    				Sizzle.error( "unsupported lang: " + lang );
    			}
    			lang = lang.replace( runescape, funescape ).toLowerCase();
    			return function( elem ) {
    				var elemLang;
    				do {
    					if ( ( elemLang = documentIsHTML ?
    						elem.lang :
    						elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) {
    
    						elemLang = elemLang.toLowerCase();
    						return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
    					}
    				} while ( ( elem = elem.parentNode ) && elem.nodeType === 1 );
    				return false;
    			};
    		} ),
    
    		// Miscellaneous
    		"target": function( elem ) {
    			var hash = window.location && window.location.hash;
    			return hash && hash.slice( 1 ) === elem.id;
    		},
    
    		"root": function( elem ) {
    			return elem === docElem;
    		},
    
    		"focus": function( elem ) {
    			return elem === document.activeElement &&
    				( !document.hasFocus || document.hasFocus() ) &&
    				!!( elem.type || elem.href || ~elem.tabIndex );
    		},
    
    		// Boolean properties
    		"enabled": createDisabledPseudo( false ),
    		"disabled": createDisabledPseudo( true ),
    
    		"checked": function( elem ) {
    
    			// In CSS3, :checked should return both checked and selected elements
    			// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
    			var nodeName = elem.nodeName.toLowerCase();
    			return ( nodeName === "input" && !!elem.checked ) ||
    				( nodeName === "option" && !!elem.selected );
    		},
    
    		"selected": function( elem ) {
    
    			// Accessing this property makes selected-by-default
    			// options in Safari work properly
    			if ( elem.parentNode ) {
    				// eslint-disable-next-line no-unused-expressions
    				elem.parentNode.selectedIndex;
    			}
    
    			return elem.selected === true;
    		},
    
    		// Contents
    		"empty": function( elem ) {
    
    			// http://www.w3.org/TR/selectors/#empty-pseudo
    			// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
    			//   but not by others (comment: 8; processing instruction: 7; etc.)
    			// nodeType < 6 works because attributes (2) do not appear as children
    			for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
    				if ( elem.nodeType < 6 ) {
    					return false;
    				}
    			}
    			return true;
    		},
    
    		"parent": function( elem ) {
    			return !Expr.pseudos[ "empty" ]( elem );
    		},
    
    		// Element/input types
    		"header": function( elem ) {
    			return rheader.test( elem.nodeName );
    		},
    
    		"input": function( elem ) {
    			return rinputs.test( elem.nodeName );
    		},
    
    		"button": function( elem ) {
    			var name = elem.nodeName.toLowerCase();
    			return name === "input" && elem.type === "button" || name === "button";
    		},
    
    		"text": function( elem ) {
    			var attr;
    			return elem.nodeName.toLowerCase() === "input" &&
    				elem.type === "text" &&
    
    				// Support: IE<8
    				// New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
    				( ( attr = elem.getAttribute( "type" ) ) == null ||
    					attr.toLowerCase() === "text" );
    		},
    
    		// Position-in-collection
    		"first": createPositionalPseudo( function() {
    			return [ 0 ];
    		} ),
    
    		"last": createPositionalPseudo( function( _matchIndexes, length ) {
    			return [ length - 1 ];
    		} ),
    
    		"eq": createPositionalPseudo( function( _matchIndexes, length, argument ) {
    			return [ argument < 0 ? argument + length : argument ];
    		} ),
    
    		"even": createPositionalPseudo( function( matchIndexes, length ) {
    			var i = 0;
    			for ( ; i < length; i += 2 ) {
    				matchIndexes.push( i );
    			}
    			return matchIndexes;
    		} ),
    
    		"odd": createPositionalPseudo( function( matchIndexes, length ) {
    			var i = 1;
    			for ( ; i < length; i += 2 ) {
    				matchIndexes.push( i );
    			}
    			return matchIndexes;
    		} ),
    
    		"lt": createPositionalPseudo( function( matchIndexes, length, argument ) {
    			var i = argument < 0 ?
    				argument + length :
    				argument > length ?
    					length :
    					argument;
    			for ( ; --i >= 0; ) {
    				matchIndexes.push( i );
    			}
    			return matchIndexes;
    		} ),
    
    		"gt": createPositionalPseudo( function( matchIndexes, length, argument ) {
    			var i = argument < 0 ? argument + length : argument;
    			for ( ; ++i < length; ) {
    				matchIndexes.push( i );
    			}
    			return matchIndexes;
    		} )
    	}
    };
    
    

    Sizzle源码分析(一) 基本概念

    Sizzle源码分析(二) 工具方法

    Sizzle源码分析(三) 兼容处理

    Sizzle源码分析(四) sizzle静态方法分析 Sizzle源码分析(四) sizzle静态方法分析


    起源地下载网 » Sizzle源码分析(四) Sizzle静态方法分析

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元