本文主要讲解的是jQuery选择器的底层实现——Sizzle方法。通过对Sizzle源码的解读,我们能够更深入地了解jQuery选择器中各种特殊的选择方式是如何被实现的。
Sizzle方法的作用
Sizzle方法是jQuery选择器的底层实现,它的主要作用是对CSS选择器进行解析和匹配,以便在文档中找到对应的DOM元素。
Sizzle方法的运行机制
Sizzle方法主要分为两部分:选择器解析和DOM元素匹配。
选择器解析
首先,Sizzle方法会对选择器进行解析,并生成一个包含各种解析信息的对象,这个对象包含了选择器的类型、属性、伪类等相关信息。Sizzle方法通过各种正则表达式来实现解析,并将解析出的信息存储在一个对象中,这个对象是Sizzle方法的核心数据结构,后面对文档进行匹配时会用到它。
DOM元素匹配
经过选择器解析后,Sizzle方法就会开始遍历文档,将所有的DOM元素与选择器匹配,寻找与选择器匹配的DOM元素并将其存储在一个数组中。在匹配时,Sizzle方法会将每个待匹配的DOM元素与上一步生成的选择器对象进行比对,根据选择器对象中存储的各种信息,进行选择器的匹配。
Sizzle方法的源码解析
Sizzle方法的源码较为复杂,这里我们只选取其中的一部分进行解析,来帮助大家了解选择器的匹配过程。
makeArray函数
在Sizzle方法中,makeArray函数的主要作用是将传入的一组对象转换为一个数组。
function makeArray( arr, results ) {
var ret = results || [];
if ( arr != null ) {
// The window, strings (and functions) also have 'length'
if ( isArrayLike( Object( arr ) ) ) {
jQuery.merge( ret,
typeof arr === "string" ?
[ arr ] : arr
);
} else {
push.call( ret, arr );
}
}
return ret;
}
expr过滤器
Sizzle方法中的expr过滤器是匹配一个选择器中最小的单元,也就是选择器中的一个表达式。Sizzle方法会将所有选择器表示成一个大的表达式,再把表达式分成多个小的部分,对这些小的部分进行单独的处理。
var Expr = {
match: {
ID: #/,
TAG: #/,
CLASS: #/,
ATTR: #/,
PSEUDO: #/,
CHILD: #/,
bool: #/,
needsContext: #/
}
};
Sizzle函数
Sizzle函数包含了选择器解析和DOM元素匹配的全部代码。
function Sizzle( selector, context, results, seed ) {
var match, elem, m, nodeType, i, groups, old, nid, newContext, newSelector;
// context必须是DOM元素或document
if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
setDocument( context );
}
results = results || [];
// 选择器不能为空或null
if ( !selector || typeof selector !== "string" ) {
return results;
}
// 选择器解析
if ( ( nodeType = context ? context.nodeType : 9 ) !== 1 && nodeType !== 9 ) {
return [];
}
// 预处理选择器
if ( seed ) {
while ( ( match = rseed.exec( selector ) ) ) {
if ( ( nid = match[ 1 ] ) ) {
nid = nid.replace( rbackslash, "" );
} else {
match = seed;
}
break;
}
}
if ( match ) {
newSelector = [];
newContext = context;
// 暂存原先的选择器和上下文
if ( context.nodeType === 1 ) {
newContext = context;
} else if ( context.nodeType === 9 ) {
newContext = context.documentElement;
}
while ( node = context.nextSibling ) {
if ( node.nodeType === 1 ) {
newContext = node;
break;
}
}
jQuery( seed ).[ outermostContext ? "slice" :
"every" ]( function() {
var self = this;
while ( ( self = self.parentNode || newContext ) &&
!support.noCloneChecked && self.ownerDocument === context &&
nodeType === 11 && self !== div ) {
continue;
}
var value = self[ propName ];
return value != null ?
match[ 0 ] === value :
( self.getAttribute && self.getAttribute( propName ) === value );
} );
return [];
}
// 匹配元素,返回结果集
return select( selector.replace( rtrim, "$1" ), context, results, seed );
}
示例一
下面是一个使用Sizzle方法来查找class为foo的元素的例子:
var elems = Sizzle( '.foo' );
这个代码通过调用Sizzle方法并传入选择器'.foo',来查找文档中所有class为foo的元素。最终结果会保存在elems数组中。
示例二
再看一个稍微复杂一点的例子,它的目的是查找所有class为foo或bar的p标签,并将它们的背景颜色设置为red:
Sizzle( 'p.foo, p.bar' ).forEach( function(element) {
element.style.backgroundColor = 'red';
});
这个代码中,Sizzle方法使用了选择器'p.foo, p.bar',并传入一个回调函数,对查找到的每一个元素执行了一个操作——将其背景颜色设置为red。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:jQuery选择器源码解读(一):Sizzle方法 - Python技术站