Compare commits

...

2 Commits

@ -977,142 +977,144 @@
* @param {String} type - input元素的类型
* @returns {Function} - 一个函数用于判断给定的元素是否是一个特定类型的input
*/
// `createInputPseudo`函数用于创建一个新的函数,这个新函数可以用来判断给定的元素是否是特定类型的`input`元素,具体的类型由传入的参数`type`指定。
function createInputPseudo( type ) {
// 返回一个匿名函数,这个匿名函数会接收一个元素`elem`作为参数,用于判断该元素是否符合特定类型的`input`元素的条件。
return function( elem ) {
var name = elem.nodeName.toLowerCase(); // 获取元素的节点名称并转换为小写
return name === "input" && elem.type === type; // 判断元素是否是一个特定类型的input
// 获取元素的节点名称并转换为小写形式,方便后续进行统一的比较判断,例如将`<INPUT>`转换为`input`,避免因大小写不同导致的判断失误。
var name = elem.nodeName.toLowerCase();
// 判断元素是否是一个`input`元素(通过比较节点名称是否为`input`),并且其`type`属性是否与传入的`type`参数相匹配,只有这两个条件都满足时才返回`true`,表示该元素是符合要求的特定类型的`input`元素,否则返回`false`。
return name === "input" && elem.type === type;
};
}
// 创建一个函数,用于生成一个判断元素是否为特定类型按钮的函数
/**
* @param {String} type - 按钮的类型
* @returns {Function} - 一个函数用于判断给定的元素是否是一个特定类型的按钮
*/
function createButtonPseudo( type ) {
return function( elem ) {
var name = elem.nodeName.toLowerCase(); // 获取元素的节点名称并转换为小写
// 判断元素是否是一个input或button并且其type属性与给定的类型相匹配
return (name === "input" || name === "button") && elem.type === type;
};
}
// `createButtonPseudo`函数用于创建一个函数,该函数可生成一个用于判断元素是否为特定类型按钮的函数,按钮类型由传入的参数`type`来指定。
// 此函数有详细的文档注释,说明它接收一个表示按钮类型的字符串参数,并返回一个可用于判断给定元素是否是特定类型按钮的函数。
function createButtonPseudo( type ) {
return function( elem ) {
var name = elem.nodeName.toLowerCase(); // 获取元素的节点名称并转换为小写形式,便于后续统一比较判断元素类型。
// 判断元素是否是一个`input`元素或者`button`元素(通过比较节点名称是否为`input`或者`button`),并且其`type`属性是否与给定的`type`参数相匹配,只要满足这两个条件就返回`true`,表示该元素是符合要求的特定类型的按钮元素,否则返回`false`。
return (name === "input" || name === "button") && elem.type === type;
};
}
// 创建一个函数,用于生成一个处理位置伪类的函数
/**
* @param {Function} fn - 一个函数用于根据给定的参数和种子集合计算匹配索引
* @returns {Function} - 一个函数用于根据给定的参数和种子集合以及匹配集合标记匹配的元素
*/
function createPositionalPseudo( fn ) {
return markFunction(function( argument ) {
argument = +argument; // 将参数转换为数字
return markFunction(function( seed, matches ) {
var j,
matchIndexes = fn( [], seed.length, argument ), // 根据参数和种子集合计算匹配索引
i = matchIndexes.length;
// 遍历匹配索引,标记匹配的元素
while ( i-- ) {
if ( seed[ (j = matchIndexes[i]) ] ) {
seed[j] = !(matches[j] = seed[j]);
}
}
});
});
}
// `createPositionalPseudo`函数用于创建一个函数,该函数可生成一个处理位置伪类相关逻辑的函数,它接收一个函数`fn`作为参数,基于这个`fn`来构建更复杂的用于处理位置伪类的函数逻辑。
function createPositionalPseudo( fn ) {
return markFunction(function( argument ) {
// 将传入的参数`argument`转换为数字类型,因为在后续的计算或比较等操作中可能需要数字类型的数据,通过前置`+`操作符可以将能转换为数字的参数转换为数字(例如`+"123"`会转换为数字`123`,如果参数本身不能转换为数字则会得到`NaN`)。
argument = +argument;
return markFunction(function( seed, matches ) {
var j,
// 调用传入的`fn`函数(这个`fn`函数应该是用于根据给定的参数和种子集合计算匹配索引的函数,具体功能由外部传入的`fn`实现),传入空数组、种子集合的长度以及转换后的参数`argument`,并将计算得到的匹配索引结果存储在`matchIndexes`变量中,用于后续标记匹配元素等操作。
matchIndexes = fn( [], seed.length, argument ),
i = matchIndexes.length;
// 通过`while`循环从后往前遍历匹配索引数组(`i--`实现从后往前遍历,这样在对数组元素进行操作时不会影响前面还未处理的元素索引情况),每次循环获取当前索引对应的索引值`j``j = matchIndexes[i]`),用于后续判断和操作种子集合中的元素。
while ( i-- ) {
// 判断种子集合`seed`中索引为`j`的元素是否存在即是否为真值在JavaScript中非`null`、非`undefined`、非`0`、非空字符串等情况都为真值),如果存在,则进行以下操作。
if ( seed[ (j = matchIndexes[i]) ] ) {
// 将种子集合`seed`中索引为`j`的元素取反赋值给自身(`seed[j] =!(matches[j] = seed[j])`这一步操作相对复杂些,它先将`seed[j]`的值赋给`matches[j]`,然后对`seed[j]`的值取反再赋值给`seed[j]`,这样就实现了对匹配元素的一种标记操作,具体的标记逻辑和作用需要结合更完整的功能需求来理解,大致是通过改变种子集合中对应元素的值来表示是否匹配等情况)。
seed[j] =!(matches[j] = seed[j]);
}
}
});
});
}
// 检查一个节点是否可以作为Sizzle的上下文
/**
* @param {Element|Object=} context - 要检查的上下文
* @returns {Element|Object|Boolean} - 如果上下文可接受则返回该节点否则返回falsy值
*/
function testContext( context ) {
return context && typeof context.getElementsByTagName !== "undefined" && context;
}
// `testContext`函数用于检查一个节点是否可以作为Sizzle的上下文也就是判断传入的节点是否满足作为Sizzle操作的有效上下文的条件。
function testContext( context ) {
// 返回判断结果,判断逻辑为:首先判断`context`是否存在因为在JavaScript中`null`、`undefined`等情况为假值,如果`context`不存在则不符合作为上下文的基本条件),并且判断`context`对象是否具有`getElementsByTagName`方法因为在Sizzle相关操作中很多时候需要通过这个方法来查找元素等所以作为有效的上下文应该具备这个方法如果这两个条件都满足则返回`context`本身表示该节点可以作为Sizzle的上下文否则返回假值比如`null`、`undefined`、`false`等表示不符合条件)。
return context && typeof context.getElementsByTagName!== "undefined" && context;
}
// 暴露支持变量以便于使用
support = Sizzle.support = {};
// 将`support`变量暴露出来,并赋值为`Sizzle`对象的`support`属性(这里`Sizzle`应该是一个全局的或者重要的核心对象,`support`属性用于存储一些和浏览器支持特性等相关的信息,通过这样的赋值使得外部代码可以方便地访问和操作这些支持特性相关的数据),便于在其他地方使用这些支持特性相关的变量和逻辑。
support = Sizzle.support = {};
// 检测XML节点
/**
* @param {Element|Object} elem - 一个元素或文档对象
* @returns {Boolean} - 如果elem是一个非HTML的XML节点则返回true否则返回false
*/
isXML = Sizzle.isXML = function( elem ) {
var documentElement = elem && (elem.ownerDocument || elem).documentElement;
return documentElement ? documentElement.nodeName !== "HTML" : false;
};
// `isXML`函数用于检测一个元素或文档对象是否是一个非HTML的XML节点也就是判断给定的`elem`是否属于XML类型且不是HTML类型的节点。
function isXML( elem ) {
// 获取元素对应的文档元素,通过判断`elem`是否存在,然后获取它的`ownerDocument`(如果存在则获取拥有该元素的文档对象,如果不存在则直接使用`elem`本身,因为`elem`本身可能就是文档对象),再获取这个文档对象的`documentElement`在DOM中`documentElement`通常指向文档的根元素例如HTML文档的`documentElement`就是`<html>`标签对应的元素),将其存储在`documentElement`变量中,用于后续判断节点类型。
var documentElement = elem && (elem.ownerDocument || elem).documentElement;
// 返回判断结果,如果获取到了`documentElement`(说明`elem`是有对应的文档元素的,符合进一步判断的条件),则判断其节点名称是否不等于`"HTML"`如果不等于说明不是HTML类型的文档元素可能是XML类型等其他类型的文档元素如果满足则返回`true`表示是一个非HTML的XML节点如果没有获取到`documentElement`(说明`elem`不符合要求或者不存在有效的对应文档元素),则返回`false`表示不是非HTML的XML节点。
return documentElement? documentElement.nodeName!== "HTML" : false;
}
// 设置文档相关的变量,基于当前的文档
/**
* @param {Element|Object} [doc] - 一个元素或文档对象用于设置文档
* @returns {Object} - 返回当前的文档
*/
setDocument = Sizzle.setDocument = function( node ) {
var hasCompare, parent,
doc = node ? node.ownerDocument || node : preferredDoc;
// `setDocument`函数用于设置文档相关的变量,它会基于传入的节点(如果有的话)来确定当前的文档,并更新一些全局变量以及进行一些和文档相关的特性检测和事件绑定等操作,函数也被赋值给`Sizzle`对象的`setDocument`属性,方便从`Sizzle`对象上进行调用。
function setDocument( node ) {
var hasCompare, parent,
// 根据传入的节点`node`来确定当前的文档,如果`node`存在,则获取它的`ownerDocument`(拥有该节点的文档对象)或者直接使用`node`本身(如果`node`本身就是文档对象),如果`node`不存在,则使用之前定义的`preferredDoc`(应该是一个默认的优先使用的文档对象,通常可能就是全局的`document`对象或者根据某种规则确定的主要文档对象)作为当前的文档,并将其存储在`doc`变量中。
doc = node? node.ownerDocument || node : preferredDoc;
// 如果文档无效或已选择,则提前返回
if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
return document;
}
// 如果获取到的文档`doc`就是全局的`document`对象说明不需要重新设置文档了或者文档的节点类型不是9在DOM中节点类型9代表文档节点如果不是文档节点则不符合要求又或者文档没有`documentElement`(即没有有效的根元素,不符合正常文档的结构要求),那么直接返回全局的`document`对象,不进行后续的设置操作,因为当前的文档不符合条件或者就是已经正确的文档了。
if ( doc === document || doc.nodeType!== 9 ||!doc.documentElement ) {
return document;
}
// 更新全局变量
document = doc;
docElem = document.documentElement;
documentIsHTML = !isXML( document );
// 支持IE 9-11, Edge
// 访问iframe文档后卸载时会抛出“权限被拒绝”错误jQuery #13936
if ( (parent = document.defaultView) && parent.top !== parent ) {
// 支持IE 11
if ( parent.addEventListener ) {
parent.addEventListener( "unload", unloadHandler, false );
// 支持IE 9 - 10 only
} else if ( parent.attachEvent ) {
parent.attachEvent( "onunload", unloadHandler );
}
}
// 更新全局变量,将`document`变量(应该是在全局范围内使用的表示当前文档的变量)设置为新确定的`doc`,将`docElem`变量(应该是用于表示文档根元素的变量,在后续操作中可能经常会用到文档根元素)设置为新文档的`documentElement`(即新文档的根元素),同时通过调用`isXML`函数判断新文档是否是HTML文档并将结果取反后赋值给`documentIsHTML`变量用于记录文档是否是HTML文档方便后续根据文档类型进行不同的操作逻辑
document = doc;
docElem = document.documentElement;
documentIsHTML =!isXML( document );
// 支持IE 9 - 11, Edge这里注释说明了以下代码针对这些浏览器版本的支持情况
// 访问`iframe`文档后卸载时会抛出“权限被拒绝”错误jQuery #13936这里应该是在项目的问题记录中提到了在这种特定情况下会出现的错误编号及相关描述以下是针对这个问题的处理逻辑通过判断文档的`defaultView`(在浏览器中,`defaultView`通常可以获取到与文档关联的窗口对象等信息)是否存在,并且判断其`top`属性(在多窗口、多文档场景下,`top`属性指向最顶层的窗口对象)是否不等于自身(用于判断是否是在`iframe`等嵌套文档场景下)来确定是否需要进行事件绑定操作。
if ( (parent = document.defaultView) && parent.top!== parent ) {
// 支持IE 11说明以下代码在IE 11浏览器中的支持情况
if ( parent.addEventListener ) {
// 如果窗口对象支持`addEventListener`方法(现代浏览器常用的添加事件监听器的方式),则添加一个`"unload"`事件监听器,当文档卸载时会触发对应的`unloadHandler`函数(这里`unloadHandler`函数应该是在外部定义的用于处理文档卸载相关逻辑的函数,代码中未完整展示其具体实现),并且设置事件传播方式为`false`(表示在冒泡阶段不传播该事件,具体的事件传播机制相关知识可以进一步查阅资料了解)。
parent.addEventListener( "unload", unloadHandler, false );
// 支持IE 9 - 10 only说明以下代码仅在IE 9到IE 10浏览器中支持的情况
} else if ( parent.attachEvent ) {
// 如果窗口对象不支持`addEventListener`方法但支持`attachEvent`方法IE浏览器旧版本中用于添加事件监听器的方式则添加一个`"onunload"`事件监听器(注意这里的事件名称格式和`addEventListener`有所不同,需要按照`attachEvent`的要求写为`"onunload"`),同样也是在文档卸载时触发`unloadHandler`函数,进行相应的卸载相关逻辑处理。
parent.attachEvent( "onunload", unloadHandler );
}
}
/* Attributes
---------------------------------------------------------------------- */
/* Attributes
---------------------------------------------------------------------- */
// 支持IE<8
// 验证getAttribute是否真正返回属性而不是属性除了IE8的布尔值
support.attributes = assert(function( div ) {
div.className = "i";
return !div.getAttribute("className");
});
// 支持IE<8说明以下代码在IE 8及以下版本浏览器中的支持情况
// 验证`getAttribute`是否真正返回属性而不是属性除了IE8的布尔值这里可能是针对IE 8浏览器在处理布尔类型属性获取时存在的特殊情况进行验证具体需要结合更多背景知识了解从注释大致能判断是对`getAttribute`方法获取属性的准确性进行测试
support.attributes = assert(function( div ) {
div.className = "i";
return!div.getAttribute("className");
});
/* getElement(s)By*
---------------------------------------------------------------------- */
/* getElement(s)By*
---------------------------------------------------------------------- */
// 检查getElementsByTagName("*")是否只返回元素
support.getElementsByTagName = assert(function( div ) {
div.appendChild( document.createComment("") );
return !div.getElementsByTagName("*").length;
});
// 检查`getElementsByTagName("*")`是否只返回元素,通过调用`assert`函数(前面定义的用于进行元素支持测试的函数,会创建一个`<div>`元素并应用传入的函数进行测试,最后返回布尔结果),传入一个匿名函数,在这个匿名函数内部创建一个`<div>`元素,并向其添加一个注释节点(通过`appendChild`方法添加一个由`document.createComment("")`创建的注释节点),然后判断通过`getElementsByTagName("*")`方法获取到的所有元素集合的长度是否为0如果为0则说明只返回了元素因为注释节点不属于元素正常情况下不应该被`getElementsByTagName("*")`获取到),返回`true`表示符合要求,否则返回`false`表示不符合要求,最后将这个测试结果赋值给`support.getElementsByTagName`变量,用于记录浏览器是否支持`getElementsByTagName("*")`方法只返回元素这一特性。
support.getElementsByTagName = assert(function( div ) {
div.appendChild( document.createComment("") );
return!div.getElementsByTagName("*").length;
});
// 支持IE<9
support.getElementsByClassName = rnative.test( document.getElementsByClassName );
// 支持IE<9说明以下代码在IE 9及以下版本浏览器中的支持情况
// 通过`rnative.test`方法(这里`rnative`应该是一个正则表达式或者具有`test`方法用于检测某种情况的对象,具体功能需结合更多代码了解,从这里大致判断是用于检测`document.getElementsByClassName`是否符合某种原生支持的情况)检测浏览器是否原生支持`getElementsByClassName`方法,并将结果赋值给`support.getElementsByClassName`变量,用于记录浏览器对该方法的支持特性。
support.getElementsByClassName = rnative.test( document.getElementsByClassName );
// 支持IE<10
// 检查getElementById是否按名称返回元素
// 损坏的getElementById方法不会拾取以编程方式设置的名称
// 因此使用一种迂回的getElementsByName测试
support.getById = assert(function( div ) {
docElem.appendChild( div ).id = expando;
return !document.getElementsByName || !document.getElementsByName( expando ).length;
});
// 支持IE<10说明以下代码在IE 10及以下版本浏览器中的支持情况
// 检查`getElementById`是否按名称返回元素,也就是验证`getElementById`方法在获取元素时是否准确按照元素的ID进行查找不会出现错误的按名称等其他方式查找的情况在一些浏览器中可能存在`getElementById`方法实现不规范的问题)。
// 损坏的`getElementById`方法不会拾取以编程方式设置的名称,所以使用一种迂回的`getElementsByName`测试(这里注释说明了因为`getElementById`方法可能存在问题,所以通过`getElementsByName`方法进行一种间接的测试来判断其是否准确按名称查找元素)。
support.getById = assert(function( div ) {
docElem.appendChild( div ).id = expando;
return!document.getElementsByName ||!document.getElementsByName( expando ).length;
});
// ID查找和过滤
if ( support.getById ) {
// 如果支持getElementById则设置ID查找和过滤函数
Expr.find["ID"] = function( id, context ) {
if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
var m = context.getElementById( id );
return m ? [ m ] : [];
}
};
// ID查找和过滤相关的逻辑根据是否支持`getById`(前面通过测试判断浏览器是否支持准确的`getElementById`查找元素的功能)来分别设置不同的查找和过滤函数,以下是具体的逻辑。
if ( support.getById ) {
// 如果支持`getElementById`方法以下是设置ID查找和过滤相关的函数逻辑。
// 设置`Expr.find["ID"]`函数(这里`Expr`应该是一个外部定义的用于存储查找、过滤等相关逻辑的对象,`find`属性下面可以存储不同类型的查找函数,这里设置的是针对`ID`类型查找的函数),它接收`id`和`context`两个参数,分别表示要查找的元素的`ID`和查找的上下文(即在哪个范围内查找元素)。
// 如果上下文对象具有`getElementById`方法(说明可以在该上下文中通过`ID`查找元素并且当前文档是HTML文档通过`documentIsHTML`判断,因为不同文档类型可能对`ID`查找有不同的实现或者限制),则尝试通过`context.getElementById`方法查找具有指定`ID``id`参数)的元素,如果找到了该元素(`m`不为`null`),则返回一个只包含该元素的数组(`[m]`),表示找到了匹配的元素;如果没有找到,则返回一个空数组`[]`,表示没有找到匹配的元素。
Expr.find["ID"] = function( id, context ) {
if ( typeof context.getElementById!== "undefined" && documentIsHTML ) {
var m = context.getElementById( id );
return m? [ m ] : [];
}
};
// 设置`Expr.filter["ID"]`函数(`Expr`对象的`filter`属性下面存储的是用于过滤元素的函数,这里是针对`ID`类型的过滤函数),它接收`id`参数,表示要过滤的元素的`ID`。
// 首先将传入的`id`参数通过`runescape`和`funescape`函数(这两个函数应该是用于对字符串进行转义处理等相关操作的函数,代码中未完整展示其具体实现,但从函数名大致能判断功能,这里用于处理`ID`字符串可能存在的特殊字符等情况,确保准确匹配)进行处理,得到处理后的`attrId`。
// 然后返回一个匿名函数,这个匿名函数接收`elem`元素作为参数,用于判断该元素的`ID`属性是否与处理后的`attrId`
Expr.filter["ID"] = function( id ) {
var attrId = id.replace( runescape, funescape );
return function( elem ) {

Loading…
Cancel
Save