jQuery选择器源码解读(四):tokenize方法的Expr.preFilter
在jQuery的Sizzle引擎中,tokenize方法负责将输入的选择器划分成一个个的Token。这些Token是选择器的构成部分,是后续处理的基础。而Expr.preFilter就是在Tokenize方法中使用的一个辅助方法,用于处理一些特殊的选择器表达式。
Expr.preFilter函数的定义:
Expr.preFilter = {
"ATTR": function (match) {
match[1] = match[1].replace(runescape, funescape);
match[3] = (match[3] || match[4] || match[5] || "").replace(runescape, funescape);
if (match[2] === "~=") {
match[3] = " " + match[3] + " ";
}
return match.slice(0, 4);
},
"CHILD": function (match) {
/* ... */
},
"PSEUDO": function (match) {
/* ... */
}
};
这个函数是一个对象,包括了三个属性:ATTR、CHILD、PSEUDO。每个属性都是一个方法,用来处理对应的选择器表达式。
在tokenize方法中,在对选择器字符串进行划分之前,会遍历这个对象,对选择器表达式进行预处理。
例如,对于选择器[attr~=value],tokenize方法首先会将整个表达式分成三个Token:attr、~=、value。在对attr Token之后,就会遇到EXPR.preFilter中的ATTR属性,将Token进行处理:
match[1] = match[1].replace(runescape, funescape);
match[3] = (match[3] || match[4] || match[5] || "").replace(runescape, funescape);
if (match[2] === "~=") {
match[3] = " " + match[3] + " ";
}
return match.slice(0, 4);
这里的match是一个数组,包含了刚刚划分出来的Token:["attr", "~=", "value"]。此时preFilter的ATTR方法就将这个Token改写成了形如["attr", "~=", " value "]的形式(注意value前后有空格)。这样,后续处理就可以直接把Token的值比对在空格的情况下是否相等,而不必再特别处理。
再例如,对于选择器div:nth-child(2n),tokenize方法会将其划分成七个Token,其中第五个Token是":nth-child",此时就会遇到EXPR.preFilter中的CHILD属性。而CHILD方法的实现中,就是将":nth-child"改写成了两个Token:":nth"和"child"。
Expr.preFilter.CHILD = function(match) {
/* 匹配div:nth-child(2n) */
/* 将match[0]从":nth-child"改为":nth"和"child" */
match[1] = match[1].toLowerCase();
if (match[1].slice(0, 3) === "nth") {
/* 处理类似,":nth-child(2n)"的选择器 */
/* 如果没有指定start,默认从0开始 */
if (!match[3]) {
match[3] = "0";
}
/* 如果没有指定end,默认到最后一个元素 */
if (!match[4]) {
match[4] = "-1";
}
/* 如果指定了start,添加前缀 */
if (match[3] === "-1") {
match[2] = match[4];
match[4] = "1";
} else {
match[2] = match[4];
match[4] = match[3];
}
/* 将start和end作为额外的Token */
match[3] = (match[5] || match[6] || "0")
.replace(/^\+|\s*/g, '') + '0'.slice(match[2] < 0 ? -1 * match[2].length : 0);
match[4] = +((match[7] + match[8] || match[3] === 'odd') ? 1 : 0);
match[2] = +match[2];
} else if (match[5]) {
/* 处理类似,":first-child"的选择器 */
match[2] = match[4] = match[5];
}
return match.slice(0, 3);
};
这里通过判断选择器表达式的开头几个字符,来判断这个选择器表达式的具体类型(比如是":nth-child"还是":first-child")。然后在根据选择器表达式的不同类型,将原来的Token改写成新的Token。最终返回处理后的Token数组。
以上就是Expr.preFilter辅助方法的基本工作原理,它可以辅助tokenize函数更好地处理选择器表达式,方便后续的操作。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:jQuery选择器源码解读(四):tokenize方法的Expr.preFilter - Python技术站