前序
概要
浅析源码
var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,
((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~]) (\s*,\s*)? ((?:.|\r|\n)*)
1. (?:\((?:\([^()]+\) 2.[^()]+)+\) 3. \[(?:\[[^[\]]*\] 4. [^[\]]+)+\]|\\. 5.[^ >+~,(\[]+)+ 6.[>+~]
1.先查找页面上所有的div 2.循环所有的div,查找每个div下的p 3.合并结果
1.先查找页面上所有的p 2.循环所有的p,查找每个p的父元素 1.如果不是div,遍历上一层。 2.如果已经是顶层,排除此p。 3.如果是div,则保存此p元素。
/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/ //POS的值
当处于1的情况时:
//如果存在伪类选择符,从selector中移除,并保存在later中
// 这样一来,匹配对象便分离出来:selector(简单选择符存储器)和later(伪类选择符存储器)。
while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
later += match[0];
selector = selector.replace( Expr.match.PSEUDO, "" );
}
//构造selector,并调用Sizzle进行匹配,将结果存储在tmpSet中
selector = Expr.relative[selector] ? selector + "*" : selector;
for ( var i = 0, l = root.length; i < l; i++ ) {
Sizzle( selector, root[i], tmpSet );
}
// 最后便是filter的过滤
return Sizzle.filter( later, tmpSet );
// 这样一来,匹配对象便分离出来:selector(简单选择符存储器)和later(伪类选择符存储器)。
while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
later += match[0];
selector = selector.replace( Expr.match.PSEUDO, "" );
}
//构造selector,并调用Sizzle进行匹配,将结果存储在tmpSet中
selector = Expr.relative[selector] ? selector + "*" : selector;
for ( var i = 0, l = root.length; i < l; i++ ) {
Sizzle( selector, root[i], tmpSet );
}
// 最后便是filter的过滤
return Sizzle.filter( later, tmpSet );
//这个为特例,被正则分割的A数组长度为2,则合并数组元素,上下文则原封不动为Sizzle传递进来的context。
if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
// 完成一次匹配, 由posProcess 内部调用 filter进行匹配
// 但在匹配前,完成了一次连接选择符的操作
// 存入set,注 set 当前还不是最终的结果,其这里的set和上面的tmpSet一样,都是一个"暂时性"的结果集
set = posProcess( parts[0] + parts[1], context );
if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
// 完成一次匹配, 由posProcess 内部调用 filter进行匹配
// 但在匹配前,完成了一次连接选择符的操作
// 存入set,注 set 当前还不是最终的结果,其这里的set和上面的tmpSet一样,都是一个"暂时性"的结果集
set = posProcess( parts[0] + parts[1], context );
set = Expr.relative[ parts[0] ] ?
[ context ] :
// 否则对队列首元素进行一次简单匹配操作
Sizzle( parts.shift(), context );
[ context ] :
// 否则对队列首元素进行一次简单匹配操作
Sizzle( parts.shift(), context );
while ( parts.length ) {
// 依次对 所匹配到的 数组中元素进行 递进匹配
selector = parts.shift();
// '>' -> '>input' 的形式
if ( Expr.relative[ selector ] )
selector += parts.shift();
set = posProcess( selector, set );
// 依次对 所匹配到的 数组中元素进行 递进匹配
selector = parts.shift();
// '>' -> '>input' 的形式
if ( Expr.relative[ selector ] )
selector += parts.shift();
set = posProcess( selector, set );
当处于2的情况时:
//为ret绑定正确的返回值
var ret = seed ? //seed 为上一次调用sizzle返回值, 即前文中提到的set|tmpset
//将预匹配后的A数组(parts)中的最后元素设置为ret的expr属性,set属性设为上一次匹配的结果集。
{ expr: parts.pop(), set: makeArray(seed) } :
//如果是第一次调用,则进行匹配操作,调用find函数
// 以parts数组最末元素为当前选择符,进行匹配操作,同时设置与之相关的context
Sizzle.find( parts.pop(), parts.length === 1 && context.parentNode ? context.parentNode : context, isXML(context) );
var ret = seed ? //seed 为上一次调用sizzle返回值, 即前文中提到的set|tmpset
//将预匹配后的A数组(parts)中的最后元素设置为ret的expr属性,set属性设为上一次匹配的结果集。
{ expr: parts.pop(), set: makeArray(seed) } :
//如果是第一次调用,则进行匹配操作,调用find函数
// 以parts数组最末元素为当前选择符,进行匹配操作,同时设置与之相关的context
Sizzle.find( parts.pop(), parts.length === 1 && context.parentNode ? context.parentNode : context, isXML(context) );
if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){
// ...
// 如果支持直接获取,则将获取class的方法 直接添加进 Expr.order中 ['ID', 'NAME', 'TAG']
Expr.order.splice(1, 0, "CLASS");
//同时在find中追加对class的获取
Expr.find.CLASS = function(match, context, isXML) {
if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
return context.getElementsByClassName(match[1]);
}
};
})();
// ...
// 如果支持直接获取,则将获取class的方法 直接添加进 Expr.order中 ['ID', 'NAME', 'TAG']
Expr.order.splice(1, 0, "CLASS");
//同时在find中追加对class的获取
Expr.find.CLASS = function(match, context, isXML) {
if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
return context.getElementsByClassName(match[1]);
}
};
})();
//order: [ "ID", "NAME", "TAG" ]
// 当然,如果浏览器支持对class的直接获取时,order中就会出现class的相关匹配规则
for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
var type = Expr.order[i], match;
// 根据 type 对所传进来的expr 进行正则匹配
// match中通过正则限制了这三类匹配方式的条件。
// 1. ID: /#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,
// 2. NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,
// 3. TAG: /^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,
if ( (match = Expr.match[ type ].exec( expr )) ) {
var left = RegExp.leftContext;
//保证返回结果的正确性,如果存在\,则删除
if ( left.substr( left.length - 1 ) !== "\\" ) {
match[1] = (match[1] || "").replace(/\\/g, "");
// 根据type调用 sizzle.selector.find方法获取结果集。
set = Expr.find[ type ]( match, context, isXML );
if ( set != null ) {
//如果匹配成功,删除已经匹配的expr
expr = expr.replace( Expr.match[ type ], "" );
break;
}
}
}
}
return {set: set, expr: expr};
};
// 当然,如果浏览器支持对class的直接获取时,order中就会出现class的相关匹配规则
for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
var type = Expr.order[i], match;
// 根据 type 对所传进来的expr 进行正则匹配
// match中通过正则限制了这三类匹配方式的条件。
// 1. ID: /#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,
// 2. NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,
// 3. TAG: /^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,
if ( (match = Expr.match[ type ].exec( expr )) ) {
var left = RegExp.leftContext;
//保证返回结果的正确性,如果存在\,则删除
if ( left.substr( left.length - 1 ) !== "\\" ) {
match[1] = (match[1] || "").replace(/\\/g, "");
// 根据type调用 sizzle.selector.find方法获取结果集。
set = Expr.find[ type ]( match, context, isXML );
if ( set != null ) {
//如果匹配成功,删除已经匹配的expr
expr = expr.replace( Expr.match[ type ], "" );
break;
}
}
}
}
return {set: set, expr: expr};
};
while ( parts.length ) {
var cur = parts.pop(), pop = cur;
// 是否存在 类似这样的匹配 eg: '+', '>'等
if ( !Expr.relative[ cur ] ) {
cur = "";
} else {
//如果存在层间关系的约束 则修复 cur 和pop的指向
// eg ['div', '+', 'span'] => pop = div; cur = '+'; 并进入 relative的匹配。
pop = parts.pop();
}
// 确保拥有上下文 代码略过
Expr.relative[ cur ]( checkSet, pop, isXML(context) );
}
var cur = parts.pop(), pop = cur;
// 是否存在 类似这样的匹配 eg: '+', '>'等
if ( !Expr.relative[ cur ] ) {
cur = "";
} else {
//如果存在层间关系的约束 则修复 cur 和pop的指向
// eg ['div', '+', 'span'] => pop = div; cur = '+'; 并进入 relative的匹配。
pop = parts.pop();
}
// 确保拥有上下文 代码略过
Expr.relative[ cur ]( checkSet, pop, isXML(context) );
}
实例
- jquery.init -> jquery.prototype.find
- 进入Sizzle(对xml的判断) -> 设置parts数组等在匹配中所需要的元素 -> 根据数组长度以及调用origPos进行判断,来决定进入哪个分支,在这个实例下进入分支1
- 循环调用Sizzle进行匹配,将结果存入set中(因为在这一过程中是循环调用,所以对Sizzle的判断也是需要多次,进入哪一分支当然也会是不一样的,比如第二轮循环判断则进入分支2中进行处理) ,对于>号的处理,也会将它合并在其后的span中,构成新的选择符 ‘>span’,然后进入Expr.relative进行匹配,同时调用posProcess。
- 调用Sizzle.find 匹配除伪类以外的部分(即这里的选择器不包含:last),首先会调用Expr.find的find方法来判断是否为哪一类匹配,在这一实例中,为TAG匹配。
- 对从4步中生成的对象进行过滤,匹配’>'(这一步的匹配是由Sizzle.filter触发,由Expr.relative完成),而在匹配’span:last’时则由posProcess来触发,设置later值(:first)以及selector(span),对span的匹配和4步骤一样,重复匹配,而对:first的匹配则是第5步的重头戏,也就是调用Sizzle.filter来完成, 由此便生成了最后的匹配结果。
1.对表达式分组。 2.选择合适的处理顺序。 3.在当前的上下文里过滤要找的节点。并更新上下文。重复这一过程,直到结尾。 4.对结果排序,如果需要的话。 5.返回结果数组。
前向兼容
querySelectorAll
//如果当前document 支持 querySelectorAll方法,则将浏览器可以完成的匹配完全交给浏览器
if ( document.querySelectorAll ) (function(){
var oldSizzle = Sizzle;
// 解决Safari bug 略过 ...
Sizzle = function(query, context, extra, seed){
context = context || document;
// 因为querySelectorAll 在domElement 节点上操作时,存在bug 所以多了这样的判断
// bug info: http://ejohn.org/blog/thoughts-on-queryselectorall/
if ( !seed && context.nodeType === 9 && !isXML(context) ) {
return makeArray( context.querySelectorAll(query), extra );
}
// querySelectorAll 可用则直接返回结果,否则才调用 sizzle
return oldSizzle(query, context, extra, seed);
};
// oldSizzle 方法追加进 新的 Sizzle 中
})();
if ( document.querySelectorAll ) (function(){
var oldSizzle = Sizzle;
// 解决Safari bug 略过 ...
Sizzle = function(query, context, extra, seed){
context = context || document;
// 因为querySelectorAll 在domElement 节点上操作时,存在bug 所以多了这样的判断
// bug info: http://ejohn.org/blog/thoughts-on-queryselectorall/
if ( !seed && context.nodeType === 9 && !isXML(context) ) {
return makeArray( context.querySelectorAll(query), extra );
}
// querySelectorAll 可用则直接返回结果,否则才调用 sizzle
return oldSizzle(query, context, extra, seed);
};
// oldSizzle 方法追加进 新的 Sizzle 中
})();
扩展
// filter的简写 ':'
jQuery.expr[":"] = jQuery.expr.filters;
$.extend($.expr[':'], {
hasSpan: function(e) {
return $(e).find('span').length > 0;
}
});
jQuery.expr[":"] = jQuery.expr.filters;
$.extend($.expr[':'], {
hasSpan: function(e) {
return $(e).find('span').length > 0;
}
});
//直接用就可以了
$('div:hasSpan')....
$('div:hasSpan')....
相关推荐
Sizzle是jQuery中的核心选择器引擎,专门负责解析和执行CSS选择器。Sizzle的设计目标是独立于DOM API,使其能够在各种浏览器环境下工作,即使这些浏览器对CSS选择器的支持不完全。 在jQuery中,Sizzle引擎主要实现...
jQuery使用了名为`Sizzle`的独立选择器引擎来处理CSS选择器。`Sizzle`能够高效地解析和执行CSS选择器,包括处理复杂的组合选择器和属性选择器。在jQuery的源码中,`Sizzle`被引入并集成,使得开发者可以利用其强大的...
于是看了jquery的源码,jquery用的选择器的引擎是sizzle,是jquery的作者另一开源项目,在github上面有,号称最快的dom选择器!不到2000行代码。上面说了不是很精彩的开场白,我么来个 for example: $(‘.test’) 在...
此外,jQuery 的选择器引擎 Sizzle 更加强大,能处理更复杂的选择器表达式,并且在兼容性方面优于原生 CSS。 ### 四、性能优化 虽然属性选择器非常方便,但在大型项目中,过度使用可能会影响页面加载和渲染速度。...
jQuery支持多种选择器,包括基本选择器(如"#id"、".class"、"tag")、类别选择器(如"[attribute]"、"[attribute=value]")、组合选择器(如","、"+"、">")以及伪类和伪元素选择器(如":hover"、":first")。...
### jQuery选择器源码解读(六):Sizzle选择器匹配逻辑分析 Sizzle选择器是jQuery库中用于解析和匹配DOM元素的一个核心组件。选择器的匹配逻辑在性能优化中起着至关重要的作用,尤其是在处理复杂的CSS选择器时。...
jQuery是一个广泛使用的JavaScript库,它的核心特性之一是其强大的选择器引擎——Sizzle。Sizzle引擎使得开发者能够使用类似于CSS的语法来选取DOM元素,极大地提高了网页开发的效率。在这个"jQuery中的Sizzle引擎...
addCombinator函数是Sizzle选择器引擎中一个关键的组件,它的作用是根据提供的选择器和关系来创建一个新的函数,这个函数能够进一步筛选通过前面的筛选器已经得到的元素集合。简单来说,addCombinator用于实现诸如...
Selenium WebDriver的扩展包括jQuery / Sizzle选择器支持。 产品特点 主要 支持嵌套选择器 易于设置:安装NuGet软件包并开始与您现有的Selenium解决方案一起使用 通过与Appveyor的持续集成设置,单元和集成测试以及...
用于收集和显示 Sizzle 选择器的控制台性能统计信息的 jQuery 插件。 Sizzle 通过$.find()集成到 jQuery 中,并用于所有接受选择器字符串的方法中,例如.filter(selector) 、 .closest(selector)等。 SizzleStats ...
4. **选择器支持**:Zepto使用Sizzle选择器引擎,与jQuery相同,但某些高级CSS选择器在Zepto中可能不被支持。 5. **浏览器兼容性**:jQuery致力于广泛的浏览器兼容性,包括较老版本的IE,而Zepto主要面向现代浏览器...
Sizzle选择器是jQuery库中的一个核心功能,它允许开发者通过简单的字符串选择器来找到DOM元素。在Sizzle方法中,它执行了多项任务,包括对不同类型的单一选择器的快速解析、利用浏览器原生方法querySelectorAll获取...
三、Sizzle选择器引擎 Sizzle是jQuery的选择器引擎,负责解析CSS选择器并找到匹配的DOM元素。它采用分治策略,将复杂选择器拆解为简单的部分,逐一匹配。Sizzle支持ID选择器、类选择器、属性选择器等多种CSS2和CSS3...
Sizzle是一个独立的、开源的JavaScript选择器引擎,主要用于处理CSS选择器,是jQuery早期版本的核心部分。它为JavaScript开发者提供了一种高效的方式来查找和操作DOM(文档对象模型)中的元素,极大地简化了网页脚本...
jQuery 1.4.2 版本在性能上进行了优化,比如引入了Sizzle选择器引擎,提高了选择器的执行速度。此外,还引入了一些技巧,如deferred对象和live/delegate事件代理,以减少DOM遍历和内存占用。 总结,jQuery 1.4.2...