第二步:实现:first,:last,:eq(),even,odd,:gt(),:lt(); :header,:root,:taget; :not()。

;(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,一般路线。示例:

 var expando = "sizzle" + 1 * new Date();
var filter = {
'pseudos': markFunction(function(){ }),
'TAG': function(){ }
}
function markFunction(fn){
fn[expando] = true;
return fn;
}
function devider(selectorType){
if( filter[type][expando] ){
console.log('伪类路线')
}else{
console.log('基本路线')
}
}
devider('pseudos')

3.只要选择器中有走setMatchers路线的方法

Sizzle一步步实现所有功能(基本筛选)的更多相关文章

  1. Sizzle一步步实现所有功能(一)

    前提: 1.HTML5自带querySelectAll可以完全替代Sizlle,所以我们下面写的Sizzle,是不考虑QSA的. 2.作者考虑了大量兼容情况,比如黑莓4.6系统这样几乎接触不到的bug ...

  2. Sizzle一步步实现所有功能(层级选择)

    第二步:实现Sizzle("el,el,el..."),Sizzle("el > el"),Sizzle("el el"),Sizzl ...

  3. Excel 2010 最熟悉的陌生功能:筛选器(将当前所选内容添加到筛选器)

    使用excel2010版的同学,在进行筛选时,肯定都对这句话很熟悉:将当前所选内容添加到筛选器.但很多同学天天看到,却不知道什么是筛选器?它有什么作用. 其实,这里所指的筛选器就是储存筛选结果的一个虚 ...

  4. excel中如何筛选功能的使用

    excel中如何筛选功能的使用 excel是一款数据处理工具,可以在众多的数据中找到想要的经过处理之后的数据,而最直接方便的功能就是筛选.请阅读下文,了解如何对数据进行筛选. 如下图所示的学生成绩中, ...

  5. sizzle源码分析 (3)sizzle 不能快速匹配时 选择器流程

    如果快速匹配不成功,则会进入sizzle自己的解析顺序,主要流程如下: 总结流程如下: (1)函数sizzle是sizzle的入口,如果能querySelectAll快速匹配,则返回结果 (2)函数S ...

  6. cxGrid控件过滤筛选后如何获更新筛选后的数据集

    cxGrid控件过滤筛选后如何获更新筛选后的数据集 (2015-06-19 12:12:08) 转载▼ 标签: delphi cxgrid筛选数据集 cxgrid过滤 分类: Delphi cxGri ...

  7. Android O 正式版新功能

    ref: Android O新特性和行为变更总结zzhttp://www.cnblogs.com/bluestorm/p/7148134.html Android O正式版带来了诸多新功能,如Tens ...

  8. iOS 模糊、精确搜索匹配功能方法总结 By HL

    字符串搜索主要用于UITableView的搜索功能的筛选,过滤,查询 下面是一些流行的搜索查询方法 一.遍历搜索 for循环 根据要求:精确搜索(判读字符串相等)   模糊搜索(字符串包含) 相关知识 ...

  9. 基于.NetCore开发博客项目 StarBlog - (13) 加入友情链接功能

    系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...

随机推荐

  1. 单链表反转(递归和非递归) (Java)

    链表定义 class ListNode { int val; ListNode next; ListNode(int x) { val = x; } } 非递归实现很简单,只需要遍历一遍链表,在遍历过 ...

  2. TX enqueue DRM

  3. Qt之再谈窗体阴影

    前面就窗口阴影已经写过一篇博客,使用九宫格的思路实现的,在我看来,凡是用程序能实现的尽量不要使用图片代替(在保证效率的前提下),今天再次分享关于我的一些小见解!     先看效果:       窗口阴 ...

  4. mac 安装maven 和改动java环境变量

    一. 首先是安装maven: 步骤: 1.下载Maven tar包 http://maven.apache.org/download.cgi 2. 下载后解压到某个目录下 [html] view pl ...

  5. fseek/ftell/rewind/fgetpos/fsetpos函数使用-linux

    程序: #include<stdio.h> int main(int argc,char *argv[]) { FILE * stream; fpos_t pos; stream = fo ...

  6. ubuntu高版本环境变量问题

    在ubuntu较高的版本(博主使用的是14.10)下,可以在/etc/environment中配置环境变量,这个环境变量可能会覆盖用户~/.bashrc中配置的环境变量,这个应该引起注意.

  7. Asp.Net Web API 2

    Asp.Net Web API 2第十八课——Working with Entity Relations in OData   前言 阅读本文之前,您也可以到Asp.Net Web API 2 系列导 ...

  8. JavaScript 中 关于 this 的学习笔记

    今天上午主要学习了js中的 this ,因为之前学习面向对象时,this这个东西出现的还是很频繁的,理解的很不透彻,感觉老被JAVA的思想带进坑里,所以对它特别关注. 首先贴一个大神的一篇博客,我是通 ...

  9. jsonsql

    http://www.trentrichardson.com/jsonsql/ 可以对json数组用sql语法进行操作,主要是查询取指定字段.条件.指定字段排序及获取多少条数据,返回值json. js ...

  10. mysql 建立索引的原则

    建索引的几大原则 1. 最左前缀匹配原则,非常重要的原则,mysql会一直向右匹配直到遇到范围查询(>.<.between.like)就停止匹配,比如a 1="" an ...