3.6 Sizzle.find( expr, context, isXML )
方法Sizzle.find( expr, context, isXML )负责查找与块表达式匹配的元素集合。该方法会按照表达式类型数组Sizzle.selectors.order规定的查找顺序(ID、CLASS、NAME、TAG)逐个尝试查找,如果未找到,则查找上下文的所有后代元素(*)。
图3-3 Sizzle( selector, context, results, seed )的执行过程
方法Sizzle.find( expr, context, isXML )执行的5个关键步骤如下:
1)先用正则集合Sizzle.selectors.leftMatch中的正则确定表达式类型。
2)然后调用查找函数集Sizzle.selectors.find中对应类型的查找函数,查找匹配的元素集合。
3)然后删除块表达式中已查找过的部分。
4)如果没有找到对应类型的查找函数,则读取上下文的所有后代元素。
5)最后返回格式为{set:候选集, expr:块表达式剩余部分}的对象。
下面来看看该方法的源码实现。
1.?定义Sizzle.find( expr, context, isXML )
相关代码如下所示:
4051 Sizzle.find = function( expr, context, isXML ) {
第4051行:定义方法Sizzle.find( expr, context, isXML ),它接受3个参数:
参数expr:块表达式。
参数context:DOM元素或文档对象,作为查找时的上下文。
参数isXML:布尔值,指示是否运行在一个XML文档中。
2.?遍历表达式类型数组Sizzle.selectors.order
相关代码如下所示:
4052 var set, i, len, match, type, left;
4053
4054 if ( !expr ) {
4055 return [];
4056 }
4057
4058 for ( i = 0, len = Expr.order.length; i < len; i++ ) {
4059 type = Expr.order[i];
4060
第4054~4056行:如果块表达式expr是空字符串,则直接返回空数组[]。
第4058行:表达式类型数组Sizzle.selectors.order中定义了查找单个块表达式时的顺序,依次是ID、CLASS、NAME、TAG,其中,CLASS需要浏览器支持方法getElements
ByClassName()。关于Sizzle.selectors.order的具体说明请参见3.9.1节。
(1)确定块表达式类型Sizzle.selectors.leftMatch[ type ]
相关代码如下所示:
4061 if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
4062 left = match[1];
4063 match.splice( 1, 1 );
4064
第4061行:检查每个表达式类型type在Sizzle.selectors.leftMatch中对应的正则是否匹配块表达式expr,如果匹配,则可以确定块表达式的类型。
第4062~4063行:对象Sizzle.selectors.leftMatch中存放了表达式类型和正则的映射,正则可以用于确定块表达式的类型,并解析其中的参数。它是基于对象Sizzle.selectors.match初始化的,具体请参见3.9.2节。
(2)查找匹配元素Sizzle.selectors.find[ type ]
相关代码如下所示:
4065 if ( left.substr( left.length - 1 ) !== "\\" ) {
4066 match[1] = (match[1] || "").replace( rBackslash, "" );
4067 set = Expr.find[ type ]( match, context, isXML );
4068
第4065行:如果匹配正则的内容以反斜杠"\\"开头,表示反斜杠"\\"之后的字符被转义了,不是期望的类型,这时会认为类型匹配失败。
第4066行:过滤其中的反斜杠,以支持将某些特殊字符(例如,“#”、“.”、“[”)作为普通字符使用。举个例子,假设某个input元素的属性id是"a.b",则对应的选择器表达式应该写作$("#a\\.b"),这里替换掉了反斜杠,又会变回"a.b",因此仍然可以通过执行document.getElementsById("a.b")查找到input元素。
第4067行:调用表达式类型type在查找函数集Sizzle.selectors.find中对应的查找函数,查找匹配的元素集合。Sizzle.selectors.find中定义了ID、CLASS、NAME、TAG所对应的查找函数,具体请参见3.9.3节。
(3)删除块表达式中已查找过的部分
相关代码如下所示:
4069 if ( set != null ) {
4070 expr = expr.replace( Expr.match[ type ], "" );
4071 break;
4072 }
4073 }
4074 }
4075 }
4076
第4069~4072行:如果set不是null和undefined,表示对应的查找函数执行了查找操作,则不管有没有找到匹配元素,都将块表达式expr中已查找过的部分删除,并结束方法Sizzle.find( expr, context, isXML )的查找过程。
第4070行:用对象Sizzle.selectors.match中对应的正则来匹配已查找过的部分,具体请参见3.9.2节。
3.?如果没有找到对应类型的查找函数,则读取上下文的所有后代元素
相关代码如下所示:
4077 if ( !set ) {
4078 set = typeof context.getElementsByTagName !== "undefined" ?
4079 context.getElementsByTagName( "*" ) :
4080 [];
4081 }
4082
第4077~4081行:如果set是null或undefined,(大多数情况下)表示没有在Sizzle.selectors.find中找到对应的查找函数,例如,$(":input")会读取上下文的所有后代元素作为候选集。
4.?返回{ set:候选集, expr:块表达式剩余部分}
相关代码如下所示:
4083 return { set: set, expr: expr };
4084 };
方法Sizzle.find( expr, context, isXML )的执行过程可总结为图3-5。
图3-5 Sizzle.find( expr, context, isXML )的执行过程