3.7 Sizzle.filter( expr,
set, inplace, not )
方法Sizzle.filter( expr, set, inplace, not )负责用块表达式过滤元素集合。在该方法内部,将用过滤函数集Sizzle.selectors.filter中的过滤函数来执行过滤操作。
方法Sizzle.filter( expr, set, inplace, not )实现的5个关键步骤如下:
1)首先用正则集合Sizzle.selectors.leftMatch中的正则确定块表达式类型。
2)然后调用预过滤函数集Sizzle.selectors.preFilter中对应类型的预过滤函数,执行过滤前的修正操作。
3)调用过滤函数集Sizzle.selectors.filter[
type ]中对应类型的过滤函数,执行过滤操作,如果过滤函数返回false,则把元素集合中对应位置的元素替换为false。
4)最后删除块表达式中已过滤的部分。
5)重复第1)~4)步,直至块表达式变为空字符串。
下面来看看该方法的源码实现。
1.定义Sizzle.filter(
expr, set, inplace, not )
相关代码如下所示:
4086 Sizzle.filter = function( expr, set,
inplace, not ) {
第4086行:定义方法Sizzle.filter( expr, set, inplace, not ),它接受 4 个参数:
参数expr:块表达式。
参数set:待过滤的元素集合。
参数inplace:布尔值。如果为true,则将元素集合set中与选择器表达式不匹配的元素设置为false;如果不为true,则重新构造一个元素数组并返回,只保留匹配元素。
参数not:布尔值。如果为true,则去除匹配元素,保留不匹配元素;如果不为true,则去除不匹配元素,保留匹配元素。
2.?用块表达式expr过滤元素集合set,直到expr为空
相关代码如下所示:
4087
var match, anyFound,
4088
type, found, item, filter, left,
4089
i, pass,
4090
old = expr,
4091
result = [],
4092
curLoop = set,
4093
isXMLFilter = set && set[0] && Sizzle.isXML( set[0] );
4094
4095
while ( expr && set.length ) {
第4095行:用块表达式expr过滤元素集合set,直到expr变为空字符串。如果候选集set变为空数组,则没有必要继续执行过滤操作。
(1)遍历块过滤函数集Sizzle.selectors.filter
相关代码如下所示:
4096
for ( type in Expr.filter ) {
第4096行:遍历块过滤函数集Sizzle.selectors.filter,调用其中的过滤函数执行过滤操作。块过滤函数集Sizzle.selectors.filter中定义了PSEUDO、CHILD、ID、TAG、CLASS、ATTR、POS对应的过滤函数,具体请参见3.9.7节。
(2)确定块表达式类型Sizzle.selectors.leftMatch[ type ]
相关代码如下所示:
4097 if ( (match = Expr.leftMatch[ type
].exec( expr )) != null && match[2] ) {
4098 filter = Expr.filter[ type ];
4099 left = match[1];
4100
4101 anyFound = false;
4102
4103 match.splice(1,1);
4104
4105 if ( left.substr( left.length
- 1 ) === "\\" ) {
4106 continue;
4107 }
4108
第4097行:检查每个表达式类型type在Sizzle.selectors.leftMatch中对应的正则是否匹配块表达式expr,如果匹配,则可以确定块表达式的类型。
第4105~4107行:如果匹配正则的内容以反斜杠"\\"开头,表示反斜杠"\\"之后的字符被转义了,不是期望的类型,这时会认为类型匹配失败。
(3)调用预过滤函数Sizzle.selectors.preFilter[ type ]
相关代码如下所示:
4109 if ( curLoop === result ) {
4110 result = [];
4111 }
4112
4113 if ( Expr.preFilter[ type ] )
{
4114 match = Expr.preFilter[
type ]( match, curLoop, inplace, result, not, isXMLFilter );
4115
4116 if ( !match ) {
4117 anyFound = found =
true;
4118
4119 } else if ( match === true
) {
4120 continue;
4121 }
4122 }
4123
第4109~4111行:用于缩小候选集。
第4113~4122行:如果在预过滤函数集Sizzle.selectors.preFilter中存在对应的预过滤函数,则调用,执行过滤前的修正操作。预过滤函数负责进一步修正过滤参数,具体请参见3.9.4节。
第4116~4121行:预过滤函数有3种返回值:
false:已经执行了过滤,缩小了候选集,例如,CLASS。
true:需要继续执行预过滤,尚不到执行过滤函数的时候,例如,POS、CHILD。
字符串:修正后的过滤参数(通常是块表达式),后面会继续调用对应的过滤函数。
(4)调用过滤函数Sizzle.selectors.filter[ type ]
相关代码如下所示:
4124 if ( match ) {
4125 for ( i = 0; (item =
curLoop[i]) != null; i++ ) {
4126 if ( item ) {
4127 found = filter(
item, match, i, curLoop );
4128 pass = not ^
found;
4129
4130 if ( inplace
&& found != null ) {
4131
if (
pass ) {
4132 anyFound =
true;
4133
4134 } else {
4135 curLoop[i]
= false;
4136 }
4137
4138 } else if ( pass )
{
4139 result.push(
item );
4140 anyFound =
true;
4141 }
4142 }
4143 }
4144 }
4145
第4124~4144行:遍历元素集合curLoop,对其中的每个元素执行过滤函数,检测元素是否匹配。
第4127~4128行:变量found表示当前元素是否匹配过滤表达式;变量pass表示当前元素item是否可以通过过滤表达式的过滤。如果变量found为true,表示匹配,此时如果未指定参数not,则变量pass为true;如果变量found为false,表示不匹配,此时如果参数not为true,则变量pass为true;其他情况下,变量pass为false。
第4130~4141行:如果参数inplace为true,则将与块表达式expr不匹配的元素设置为false;如果参数inplace不是true,则重新构造一个元素数组,只保留匹配元素,即会不断地缩小元素集合。
(5)删除块表达式expr中已过滤的部分
相关代码如下所示:
4146 if ( found !== undefined ) {
4147 if ( !inplace ) {
4148
curLoop = result;
4149 }
4150
4151 expr = expr.replace(
Expr.match[ type ], "" );
4152
4153 if ( !anyFound ) {
4154 return [];
4155 }
4156
4157 break;
4158 }
4159 }
4160
}
4161
第4146行:变量found是过滤函数Sizzle.selectors.filter[ type ]的返回值,如果不等于undefined,表示至少执行过一次过滤。大多数情况下,过滤操作发生在过滤函数中,不过也可能发生在预过滤函数中,例如,CLASS、POS、CHILD。
第4147~4149行:如果参数inplace不是true,则将新构建的元素数组赋值给变量curLoop,在下次循环时,会将result再次置为空数组(见第4109~4111行),然后存放通过过滤的元素(见第4130~4141行),然后再赋值给变量curLoop,即会不断地缩小元素集合。
第4151行:删除块表达式中已过滤过的部分,直至块表达式变为空字符串。用对象Sizzle.selectors.match中对应的正则匹配已过滤过的部分,具体请参见3.9.2节。
第4153~4155行:如果没有找到可以通过过滤的元素,直接返回一个空数组。
(6)如果块表达式没有发生变化,则认为不合法
相关代码如下所示:
4162
// Improper expression
4163
if ( expr === old ) {
4164 if ( anyFound == null ) {
4165 Sizzle.error( expr );
4166
4167 } else {
4168 break;
4169 }
4170
}
4171
4172
old = expr;
4173
}
4174
4178 Sizzle.error = function( msg ) {
4179
throw new Error( "Syntax error, unrecognized expression: " +
msg );
4180 };
第4163~4172行:如果块表达式expr没有发生变化,说明前面的过滤没有生效,动不了块表达式expr分毫,此时如果没有找到可以通过过滤的元素,则认为块表达式expr不合法,抛出语法错误的异常。
3.?返回过滤后的元素集合,或缩减范围后的元素集合
相关代码如下所示:
4175
return curLoop;
4176 };
方法Sizzle.filter( expr, set, inplace, not )的执行过程可以总结为图3-6。