上面一篇文章说的Sizzle的利器之一find函数Sizzle选择器揭秘--Sizzle选择器
这篇介绍Sizzle的另一利器filter函数
1: Sizzle.filter = function(expr, set, inplace, not){
2: //将选择表达式先存起来,后面会用它来比较。curLoop代表当前循环时的结果集的值
3: var old = expr, result = [], curLoop = set, match, anyFound,
4: isXMLFilter = set && set[0] && isXML(set[0]);
5: //遍历set结果集中的元素就行遍历筛选
6: while ( expr && set.length ) {
7: //对筛选类型进行遍历 filter中对筛选类型进行了细分 筛选的类型有PSEUDO(伪选择符)CHILD ID TAG CLASS ATTR POS
8: for ( var type in Expr.filter ) {
9: //对选择字符串进行相应的参数提取 match[1]为左边剩下的部分,match[2]为过滤的实际参数
10: if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
11: //将对象类型的过滤函数赋给filter
12: var filter = Expr.filter[ type ], found, item, left = match[1];
13: anyFound = false;
14:
15: match.splice(1,1);
16: //如果匹配的类型字符处是进行转义的如 \\: 则结束此次循环进入下一次循环
17: if ( left.substr( left.length - 1 ) === "\\" ) {
18: continue;
19: }
20: //用于缩小结果集
21: if ( curLoop === result ) {
22: result = [];
23: }
24: //对结果集进行预过滤 prefilter中有 CLASS ID TAG CHILD ATTR PSEUDO POS,关于顺序问题后面介绍
25: //预处理的作用是对特殊过滤类型进行处理和对过滤类型参数进行预处理
26: if ( Expr.preFilter[ type ] ) {
27: match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
28: //预处理结果 CLASS类型预过滤总是返回false因为在prefilter["CLASS"](match, curLoop, inplace, result, not, isXML)中已经进行了过滤,故返回一直返回false(至所以返回false是为了下面if(match)判断方便)
29: //PSEUDO类型的预处理函数则有点复杂,应为所有的伪类选择器不都是一种过滤类型 当选择符是:not则PESUDO预过滤函数会就会直接处理然后返回false,同上面的CLASS一样,但是如果不是;not而使伪位置选择符或是CHILD类型
30: 如:nth-child之类则返回true。这样在filter中结束本次循环,在后面的CHILD和POS中再进行处理。如果是其他情况则返回原来的过滤参数match
31: if ( !match ) {
32: anyFound = found = true;
33: } else if ( match === true ) {
34: continue;
35: }
36: }
37: //提出特殊情况,执行以下语句
38: if ( match ) {
39: for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
40: if ( item ) {
41: 对对当前循环结果集进行过滤,filter为先前保存的过滤函数
42: found = filter( item, match, i, curLoop );
43: //found返回的是否是符合过滤条件或是过滤结果
44: var pass = not ^ !!found;
45: //inplace这个参数是表明是否改变原来的集合,如果为true则将原先结果集中符合过滤条件的设为true,否则设为true。但无论如何都会将符合条件的放到result中,同时设置各种标志位
46: if ( inplace && found != null ) {
47: if ( pass ) {
48: anyFound = true;
49: } else {
50: curLoop[i] = false;
51: }
52: } else if ( pass ) {
53: result.push( item );
54: anyFound = true;
55: }
56: }
57: }
58: }
59:
60: if ( found !== undefined ) {
61: if ( !inplace ) {
62: //缩小curLoop中的过滤范围
63: curLoop = result;
64: }
65: //如果过滤成功的话则将相应的参数位置设为“”
66: expr = expr.replace( Expr.match[ type ], "" );
67:
68: //没有符合条件的返回[]
69: if ( !anyFound ) {
70: return [];
71: }
72: //过滤成功的就跳出内层循环,在从PSEUDO到POS进行新一轮过滤
73: break;
74: }
75: }
76: }
77: //如果先后过滤字符串一样则过滤字符串有问题
78: // Improper expression
79: if ( expr === old ) {
80: if ( anyFound == null ) {
81: Sizzle.error( expr );
82: } else {
83: break;
84: }
85: }
86:
87: old = expr;
88: }
89: //最后返回最后过滤过的结果集
90: return curLoop;
91: };
其实虽然过滤和预过滤都是按照一定的过滤类型进行过滤,但是在进行匹配过滤字符换时是按照从右往左的顺序进行因为正则表达式中有一个负向前瞻(?!……)(?!.....)
举例来说一个过滤字符串 li:enabled.sel 在匹配这个字符串时先匹配PSEUDO时是匹配不成功的。最先匹配的是.sel(CLASS),然后才是:enabled 最后是li(TAG).
其实Sizzle中最重要的就是这两个函数,下面一片文章是关于Sizzle,如果这两篇文章看懂了,后面应该是很轻松。