|
|
|
@ -4306,124 +4306,203 @@ var getText = Sizzle.getText = function( elem ) {
|
|
|
|
|
return ret;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var Expr = Sizzle.selectors = {
|
|
|
|
|
order: [ "ID", "NAME", "TAG" ],
|
|
|
|
|
|
|
|
|
|
match: {
|
|
|
|
|
ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
|
|
|
|
|
CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
|
|
|
|
|
NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,
|
|
|
|
|
ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,
|
|
|
|
|
TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,
|
|
|
|
|
CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,
|
|
|
|
|
POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
|
|
|
|
|
PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
leftMatch: {},
|
|
|
|
|
|
|
|
|
|
attrMap: {
|
|
|
|
|
"class": "className",
|
|
|
|
|
"for": "htmlFor"
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
attrHandle: {
|
|
|
|
|
href: function( elem ) {
|
|
|
|
|
return elem.getAttribute( "href" );
|
|
|
|
|
// 定义Expr对象,它包含选择器引擎的一些核心属性和方法,Sizzle.selectors将其引用为Expr
|
|
|
|
|
var Expr = Sizzle.selectors = {
|
|
|
|
|
// 定义选择器匹配的优先级顺序
|
|
|
|
|
order: [ "ID", "NAME", "TAG" ],
|
|
|
|
|
|
|
|
|
|
// 定义一个对象,包含不同类型的选择器匹配正则表达式
|
|
|
|
|
match: {
|
|
|
|
|
// ID选择器,匹配以#开头的字符串,后面跟随一个或多个字母、数字、连字符、Unicode字符或转义字符
|
|
|
|
|
ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
|
|
|
|
|
// 类选择器,匹配以.开头的字符串,后面跟随一个或多个字母、数字、连字符、Unicode字符或转义字符
|
|
|
|
|
CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
|
|
|
|
|
// 名称选择器,匹配[name='value']的形式,其中value可以是字母、数字、连字符、Unicode字符或转义字符
|
|
|
|
|
NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,
|
|
|
|
|
// 属性选择器,匹配[attr=value]的形式,支持多种属性值和复杂的表达式
|
|
|
|
|
ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,
|
|
|
|
|
// 标签选择器,匹配一个或多个字母、数字、星号、连字符、Unicode字符或转义字符
|
|
|
|
|
TAG: /^((?:[\w\u00c0-\uFFFF*\-]|\\.)+)/,
|
|
|
|
|
// 子选择器,匹配:first-child, :last-child, :nth-child(n), :only-child等
|
|
|
|
|
CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,
|
|
|
|
|
// 位置选择器,匹配:nth, :eq, :gt, :lt, :first, :last, :even, :odd等
|
|
|
|
|
POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
|
|
|
|
|
// 伪类选择器,匹配形如:hover, :focus等的伪类,支持带参数的伪类如:not(.class)
|
|
|
|
|
PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
|
|
|
|
|
},
|
|
|
|
|
type: function( elem ) {
|
|
|
|
|
return elem.getAttribute( "type" );
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
relative: {
|
|
|
|
|
"+": function(checkSet, part){
|
|
|
|
|
var isPartStr = typeof part === "string",
|
|
|
|
|
isTag = isPartStr && !rNonWord.test( part ),
|
|
|
|
|
isPartStrNotTag = isPartStr && !isTag;
|
|
|
|
|
|
|
|
|
|
if ( isTag ) {
|
|
|
|
|
part = part.toLowerCase();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
|
|
|
|
|
if ( (elem = checkSet[i]) ) {
|
|
|
|
|
while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
|
|
|
|
|
// leftMatch对象,可能用于存储一些预处理或解析过程中使用的匹配信息
|
|
|
|
|
leftMatch: {},
|
|
|
|
|
|
|
|
|
|
checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
|
|
|
|
|
elem || false :
|
|
|
|
|
elem === part;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// attrMap对象,定义了一些属性名的映射,用于处理某些HTML属性在DOM中的不同表示
|
|
|
|
|
attrMap: {
|
|
|
|
|
"class": "className",
|
|
|
|
|
// class属性在DOM中对应className
|
|
|
|
|
"for": "htmlFor"
|
|
|
|
|
// for属性在DOM中对应htmlFor
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
if ( isPartStrNotTag ) {
|
|
|
|
|
Sizzle.filter( part, checkSet, true );
|
|
|
|
|
// attrHandle对象,定义了一些特定属性的处理函数
|
|
|
|
|
attrHandle: {
|
|
|
|
|
// href属性的处理函数,返回元素的href属性值
|
|
|
|
|
href: function( elem ) {
|
|
|
|
|
return elem.getAttribute( "href" );
|
|
|
|
|
},
|
|
|
|
|
// type属性的处理函数,返回元素的type属性值
|
|
|
|
|
type: function( elem ) {
|
|
|
|
|
return elem.getAttribute( "type" );
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
">": function( checkSet, part ) {
|
|
|
|
|
var elem,
|
|
|
|
|
isPartStr = typeof part === "string",
|
|
|
|
|
i = 0,
|
|
|
|
|
l = checkSet.length;
|
|
|
|
|
|
|
|
|
|
if ( isPartStr && !rNonWord.test( part ) ) {
|
|
|
|
|
part = part.toLowerCase();
|
|
|
|
|
|
|
|
|
|
for ( ; i < l; i++ ) {
|
|
|
|
|
elem = checkSet[i];
|
|
|
|
|
|
|
|
|
|
if ( elem ) {
|
|
|
|
|
var parent = elem.parentNode;
|
|
|
|
|
checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
|
|
|
|
|
// 定义一个对象,包含处理相对选择器的函数
|
|
|
|
|
relative: {
|
|
|
|
|
// "+" 选择器的处理函数,用于查找当前元素之前的相邻兄弟元素
|
|
|
|
|
"+": function(checkSet, part){
|
|
|
|
|
// 判断part是否为字符串类型
|
|
|
|
|
var isPartStr = typeof part === "string",
|
|
|
|
|
// 判断part是否为标签名(即不包含非单词字符)
|
|
|
|
|
isTag = isPartStr && !rNonWord.test( part ),
|
|
|
|
|
// 判断part是否为字符串但不是标签名(可能是一个类名、ID等)
|
|
|
|
|
isPartStrNotTag = isPartStr && !isTag;
|
|
|
|
|
|
|
|
|
|
// 如果part是标签名,则将其转换为小写
|
|
|
|
|
if ( isTag ) {
|
|
|
|
|
part = part.toLowerCase();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
for ( ; i < l; i++ ) {
|
|
|
|
|
elem = checkSet[i];
|
|
|
|
|
// 遍历checkSet中的每个元素
|
|
|
|
|
for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
|
|
|
|
|
// 获取当前遍历到的元素
|
|
|
|
|
if ( (elem = checkSet[i]) ) {
|
|
|
|
|
// 向上遍历前一个兄弟元素,直到找到一个元素节点(nodeType为1)或没有兄弟元素为止
|
|
|
|
|
while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
|
|
|
|
|
|
|
|
|
|
// 根据条件更新checkSet[i]的值
|
|
|
|
|
// 如果part不是标签名,或者elem存在且其标签名与part(小写)相同,则设置为elem或false(如果elem不存在)
|
|
|
|
|
// 如果part是具体的某个元素(通过===比较),则直接比较elem和part是否相同
|
|
|
|
|
checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
|
|
|
|
|
elem || false :
|
|
|
|
|
// 如果条件满足,设置为elem(如果存在)或false(如果不存在)
|
|
|
|
|
elem === part;
|
|
|
|
|
// 如果part是具体的元素,直接比较是否相等
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( elem ) {
|
|
|
|
|
checkSet[i] = isPartStr ?
|
|
|
|
|
elem.parentNode :
|
|
|
|
|
elem.parentNode === part;
|
|
|
|
|
// 如果part是字符串但不是标签名(可能是一个类名、ID等),则调用Sizzle的filter函数来处理
|
|
|
|
|
if ( isPartStrNotTag ) {
|
|
|
|
|
Sizzle.filter( part, checkSet, true );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// “>” 选择器的处理函数,用于查找当前元素的直接子元素
|
|
|
|
|
},
|
|
|
|
|
">": function( checkSet, part ) {
|
|
|
|
|
var elem,
|
|
|
|
|
// 当前遍历到的元素
|
|
|
|
|
isPartStr = typeof part === "string",
|
|
|
|
|
// 判断part是否为字符串类型
|
|
|
|
|
i = 0,
|
|
|
|
|
// 循环计数器
|
|
|
|
|
l = checkSet.length;
|
|
|
|
|
// checkSet的长度
|
|
|
|
|
|
|
|
|
|
// 如果part是字符串且不包含非单词字符(可能是标签名),则进行以下处理
|
|
|
|
|
if ( isPartStr && !rNonWord.test( part ) ) {
|
|
|
|
|
part = part.toLowerCase();
|
|
|
|
|
// 将part转换为小写,以确保比较时不区分大小写
|
|
|
|
|
|
|
|
|
|
// 遍历checkSet中的每个元素
|
|
|
|
|
for ( ; i < l; i++ ) {
|
|
|
|
|
elem = checkSet[i];
|
|
|
|
|
// 获取当前遍历到的元素
|
|
|
|
|
|
|
|
|
|
if ( elem ) {
|
|
|
|
|
var parent = elem.parentNode;
|
|
|
|
|
// 获取当前元素的父元素
|
|
|
|
|
// 如果当前元素的父元素的标签名与part(小写)相同,则将该父元素设置为checkSet[i]的值,否则设置为false
|
|
|
|
|
checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 注意:这里的代码片段没有包含rNonWord正则表达式的定义,也没有包含函数的结束括号和对象字面量的结束花括号。
|
|
|
|
|
} // 如果part不是简单的标签名(即包含非单词字符或未定义rNonWord导致的其他情况)
|
|
|
|
|
else {
|
|
|
|
|
// 遍历checkSet中的每个元素
|
|
|
|
|
for (; i < l; i++) {
|
|
|
|
|
elem = checkSet[i];
|
|
|
|
|
// 获取当前遍历到的元素
|
|
|
|
|
|
|
|
|
|
if (elem) {
|
|
|
|
|
// 根据part是否为字符串类型,更新checkSet[i]的值
|
|
|
|
|
// 如果是字符串,则保留elem的父元素;如果不是(可能是具体的DOM元素),则比较elem的父元素是否等于part
|
|
|
|
|
checkSet[i] = isPartStr ?
|
|
|
|
|
elem.parentNode :
|
|
|
|
|
// 如果part是字符串,则设置为elem的父元素
|
|
|
|
|
elem.parentNode === part;
|
|
|
|
|
// 如果part不是字符串(可能是DOM元素),则比较elem的父元素是否等于part
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( isPartStr ) {
|
|
|
|
|
Sizzle.filter( part, checkSet, true );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
// 如果part是字符串类型,则对checkSet进行进一步的筛选
|
|
|
|
|
// 这可能是为了处理类名、ID或其他属性选择器的情况
|
|
|
|
|
if (isPartStr) {
|
|
|
|
|
Sizzle.filter(part, checkSet, true);
|
|
|
|
|
// 调用Sizzle的filter函数进行筛选,true可能是表示某种特定行为的标志
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
// 注意:这里的代码片段是“>”选择器的处理函数的一部分,并且没有包含函数的结束括号和对象字面量的结束花括号。
|
|
|
|
|
// 此外,还假设了Sizzle.filter函数的存在和行为,以及isPartStr、checkSet、part、i和l等变量的上下文。
|
|
|
|
|
// 定义一个对象字面量,其中包含不同选择器的处理函数
|
|
|
|
|
|
|
|
|
|
// 空字符串选择器的处理函数
|
|
|
|
|
"": function(checkSet, part, isXML){
|
|
|
|
|
var nodeCheck,
|
|
|
|
|
doneName = done++,
|
|
|
|
|
checkFn = dirCheck;
|
|
|
|
|
|
|
|
|
|
if ( typeof part === "string" && !rNonWord.test( part ) ) {
|
|
|
|
|
part = part.toLowerCase();
|
|
|
|
|
nodeCheck = part;
|
|
|
|
|
checkFn = dirNodeCheck;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML );
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
var nodeCheck,
|
|
|
|
|
// 用于存储节点检查的变量(可能是标签名)
|
|
|
|
|
doneName = done++,
|
|
|
|
|
// 一个唯一标识符,可能用于跟踪检查过程的状态,`done`可能是一个外部变量,在此函数中自增
|
|
|
|
|
checkFn = dirCheck;
|
|
|
|
|
// 初始检查函数,可能用于执行一般的DOM树遍历和检查
|
|
|
|
|
|
|
|
|
|
// 如果part是字符串且不包含非单词字符,则进行以下处理
|
|
|
|
|
if ( typeof part === "string" && !rNonWord.test( part ) ) {
|
|
|
|
|
part = part.toLowerCase();
|
|
|
|
|
// 将part转换为小写
|
|
|
|
|
nodeCheck = part;
|
|
|
|
|
// 将part设置为nodeCheck,用于后续的节点检查
|
|
|
|
|
checkFn = dirNodeCheck;
|
|
|
|
|
// 将检查函数更改为dirNodeCheck,可能用于基于节点名的检查
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 调用检查函数,传入相关参数以执行检查逻辑
|
|
|
|
|
// "parentNode"表示要检查的DOM关系(在这个上下文中,可能是用于遍历父元素)
|
|
|
|
|
// part、doneName、checkSet、nodeCheck和isXML是其他必要的参数
|
|
|
|
|
checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML );
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 波浪线选择器(~)的处理函数,用于选择同一父元素下的兄弟元素
|
|
|
|
|
"~": function( checkSet, part, isXML ) {
|
|
|
|
|
var nodeCheck,
|
|
|
|
|
doneName = done++,
|
|
|
|
|
checkFn = dirCheck;
|
|
|
|
|
|
|
|
|
|
if ( typeof part === "string" && !rNonWord.test( part ) ) {
|
|
|
|
|
part = part.toLowerCase();
|
|
|
|
|
nodeCheck = part;
|
|
|
|
|
checkFn = dirNodeCheck;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML );
|
|
|
|
|
}
|
|
|
|
|
var nodeCheck, // 同上,用于存储节点检查的变量
|
|
|
|
|
doneName = done++,
|
|
|
|
|
// 同上,生成一个唯一标识符
|
|
|
|
|
checkFn = dirCheck;
|
|
|
|
|
// 同上,初始检查函数
|
|
|
|
|
|
|
|
|
|
// 如果part是字符串且不包含非单词字符,则进行与空字符串选择器相同的处理
|
|
|
|
|
if ( typeof part === "string" && !rNonWord.test( part ) ) {
|
|
|
|
|
part = part.toLowerCase();
|
|
|
|
|
// 转换为小写
|
|
|
|
|
nodeCheck = part;
|
|
|
|
|
// 设置为nodeCheck
|
|
|
|
|
checkFn = dirNodeCheck;
|
|
|
|
|
// 更改检查函数为dirNodeCheck
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 调用检查函数,但这次传入"previousSibling"作为要检查的DOM关系
|
|
|
|
|
// 这表明我们是在查找同一父元素下的前一个兄弟元素(但实际上可能是通过逻辑来查找所有匹配的兄弟元素)
|
|
|
|
|
// 注意:这里的实现细节可能有所不同,因为波浪线选择器通常需要检查所有兄弟元素,而不仅仅是前一个
|
|
|
|
|
checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML );
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
// 注意:这里的代码片段没有包含`done`变量的定义、`dirCheck`和`dirNodeCheck`函数的定义,以及对象字面量的结束花括号。
|
|
|
|
|
// 这些都是在外部定义的,可能是选择器引擎的一部分。
|
|
|
|
|
|
|
|
|
|
find: {
|
|
|
|
|
ID: function( match, context, isXML ) {
|
|
|
|
|