feature/lfe
LFE 3 weeks ago
parent 7743b2f150
commit 91168f6431

@ -6288,206 +6288,266 @@ var getText = Sizzle.getText = function( elem ) {
});
},
// before方法在当前元素之前插入内容
before: function () {
// 如果当前jQuery对象至少有一个元素并且这个元素有父节点
if (this[0] && this[0].parentNode) {
// 使用domManip方法插入内容位置在当前元素之前
return this.domManip(arguments, false, function (elem) {
this.parentNode.insertBefore(elem, this);
});
} else if ( arguments.length ) {
} else if (arguments.length) { // 如果有参数传入
// 清理参数将它们转换成一个jQuery对象数组
var set = jQuery.clean(arguments);
// 将当前jQuery对象中的元素添加到set数组末尾
set.push.apply(set, this.toArray());
// 返回一个新的jQuery对象包含set数组中的元素
return this.pushStack(set, "before", arguments);
}
},
// after方法在当前元素之后插入内容
after: function () {
// 如果当前jQuery对象至少有一个元素并且这个元素有父节点
if (this[0] && this[0].parentNode) {
// 使用domManip方法插入内容位置在当前元素的下一个兄弟节点之前即当前元素之后
return this.domManip(arguments, false, function (elem) {
this.parentNode.insertBefore(elem, this.nextSibling);
});
} else if ( arguments.length ) {
} else if (arguments.length) { // 如果有参数传入
// 创建一个新的jQuery对象包含当前元素
var set = this.pushStack(this, "after", arguments);
// 清理参数并将它们添加到set中
set.push.apply(set, jQuery.clean(arguments));
// 返回set
return set;
}
},
// keepData is for internal use only--do not document
// remove方法移除当前元素
remove: function (selector, keepData) {
// 遍历当前jQuery对象中的每个元素
for (var i = 0, elem; (elem = this[i]) != null; i++) {
// 如果没有指定选择器或者当前元素匹配选择器
if (!selector || jQuery.filter(selector, [elem]).length) {
// 如果没有指定keepData并且元素是DOM元素
if (!keepData && elem.nodeType === 1) {
// 清理元素及其所有子元素上的数据
jQuery.cleanData(elem.getElementsByTagName("*"));
jQuery.cleanData([elem]);
}
// 如果元素有父节点,则从父节点中移除该元素
if (elem.parentNode) {
elem.parentNode.removeChild(elem);
}
}
}
// 返回当前jQuery对象
return this;
},
// empty方法移除当前元素的所有子元素
empty: function () {
// 遍历当前jQuery对象中的每个元素
for (var i = 0, elem; (elem = this[i]) != null; i++) {
// Remove element nodes and prevent memory leaks
// 如果元素是DOM元素
if (elem.nodeType === 1) {
// 清理元素上的所有子元素的数据
jQuery.cleanData(elem.getElementsByTagName("*"));
}
// Remove any remaining nodes
// 移除元素的所有子节点
while (elem.firstChild) {
elem.removeChild(elem.firstChild);
}
}
// 返回当前jQuery对象
return this;
},
// clone方法克隆当前元素
clone: function (dataAndEvents, deepDataAndEvents) {
// 设置dataAndEvents和deepDataAndEvents的默认值
dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
// 返回一个新的jQuery对象包含当前元素的克隆
return this.map(function () {
return jQuery.clone(this, dataAndEvents, deepDataAndEvents);
});
},
// html方法获取或设置当前元素的HTML内容
html: function (value) {
// 使用jQuery.access方法根据是否传入value值来获取或设置HTML内容
return jQuery.access(this, function (value) {
var elem = this[0] || {},
// 获取第一个元素,如果不存在则为空对象
i = 0,
l = this.length;
// 当前jQuery对象的长度
// 如果没有传入value值则获取HTML内容
if (value === undefined) {
return elem.nodeType === 1 ?
// 如果元素是DOM元素
elem.innerHTML.replace(rinlinejQuery, "") :
// 移除jQuery特有的标记
null;
}
// 如果value是字符串并且满足特定条件不触发innerHTML的bug
if (typeof value === "string" && !rnoInnerhtml.test(value) &&
(jQuery.support.leadingWhitespace || !rleadingWhitespace.test(value)) &&
!wrapMap[(rtagName.exec(value) || ["", ""])[1].toLowerCase()]) {
// 尝试直接设置innerHTML
value = value.replace(rxhtmlTag, "<$1></$2>");
try {
for (; i < l; i++) {
// Remove element nodes and prevent memory leaks
elem = this[i] || {};
// 获取当前元素
if (elem.nodeType === 1) {
// 如果元素是DOM元素
jQuery.cleanData(elem.getElementsByTagName("*"));
// 清理数据
elem.innerHTML = value;
// 设置innerHTML
}
}
elem = 0;
// 重置elem
// If using innerHTML throws an exception, use the fallback method
} catch(e) {}
// 如果使用innerHTML失败则使用备用方法
} catch (e) {
}
}
// 如果value值存在则清空当前元素的内容并追加value值
if (elem) {
this.empty().append(value);
}
}, null, value, arguments.length);
},
// 定义一个 replaceWith 方法,用于替换当前匹配的元素集合
replaceWith: function (value) {
// 确保至少有一个元素且该元素有父节点
if (this[0] && this[0].parentNode) {
// Make sure that the elements are removed from the DOM before they are inserted
// this can help fix replacing a parent with child elements
// 如果传入的值是一个函数,则对每个匹配的元素执行此函数,并替换元素
if (jQuery.isFunction(value)) {
return this.each(function (i) {
var self = jQuery(this), old = self.html();
// 获取当前元素并保存其HTML内容
self.replaceWith(value.call(this, i, old));
// 调用函数并替换当前元素
});
}
// 如果传入的值不是字符串则将其转换为jQuery对象并从DOM中分离
if (typeof value !== "string") {
value = jQuery(value).detach();
}
// 对每个匹配的元素执行替换操作
return this.each(function () {
var next = this.nextSibling,
// 获取当前元素的下一个兄弟节点
parent = this.parentNode;
// 获取当前元素的父节点
jQuery(this).remove();
// 从DOM中移除当前元素
// 如果存在下一个兄弟节点,则在其之前插入新元素
if (next) {
jQuery(next).before(value);
} else {
// 否则,将新元素追加到父节点的末尾
jQuery(parent).append(value);
}
});
} else {
// 如果没有匹配的元素或元素没有父节点,则根据传入值的不同进行处理
return this.length ?
this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
this;
this.pushStack(jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value) : // 如果传入值是一个函数则执行它并返回结果否则直接返回jQuery对象
this; // 如果没有匹配的元素则直接返回当前jQuery对象
}
},
// 定义一个 detach 方法用于从DOM中分离元素
detach: function (selector) {
return this.remove(selector, true);
// 调用 remove 方法并设置第二个参数为 true 以实现分离而非删除
},
// 定义一个 domManip 方法用于在DOM中进行复杂的操作如插入、删除、替换等
domManip: function (args, table, callback) {
var results, first, fragment, parent,
value = args[0],
// 获取传入的操作值
scripts = [];
// 用于存储脚本元素的数组
// We can't cloneNode fragments that contain checked, in WebKit
// 如果不支持复选框的克隆,并且传入的值是字符串且包含复选框,则对每个元素单独处理
if (!jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test(value)) {
return this.each(function () {
jQuery(this).domManip(args, table, callback, true);
// 递归调用并设置额外的参数
});
}
// 如果传入的值是一个函数则对每个匹配的元素执行此函数并传入参数进行DOM操作
if (jQuery.isFunction(value)) {
return this.each(function (i) {
var self = jQuery(this);
args[0] = value.call(this, i, table ? self.html() : undefined);
self.domManip( args, table, callback );
// 调用函数并更新传入值
self.domManip(args, table, callback); // 递归调用 domManip 方法
});
}
// 确保有至少一个匹配的元素
if (this[0]) {
parent = value && value.parentNode;
// 获取传入值的父节点
// If we're in a fragment, just use that instead of building a new one
// 如果传入的值是一个文档片段且其子节点数量与当前匹配的元素数量相同,则直接使用该片段
if (jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length) {
results = { fragment: parent };
results = {fragment: parent}; // 设置结果对象,包含文档片段
} else {
// 否则,根据传入的值和当前匹配的元素创建一个新的文档片段
results = jQuery.buildFragment(args, this, scripts);
}
fragment = results.fragment;
fragment = results.fragment; // 获取文档片段
// 如果文档片段只有一个子节点,则直接使用该子节点
if (fragment.childNodes.length === 1) {
first = fragment = fragment.firstChild;
} else {
// 否则,使用文档片段的第一个子节点
first = fragment.firstChild;
}
if (first) {
table = table && jQuery.nodeName(first, "tr");
// 检查第一个子节点是否为表格行
// 对每个匹配的元素执行回调函数,传入处理后的文档片段或子节点
for (var i = 0, l = this.length, lastIndex = l - 1; i < l; i++) {
callback.call(
table ?
root(this[i], first) :
// 如果是表格行,则使用特殊方法处理
this[i],
// Make sure that we do not leak memory by inadvertently discarding
// the original fragment (which might have attached data) instead of
// using it; in addition, use the original fragment object for the last
// item instead of first because it can end up being emptied incorrectly
// in certain situations (Bug #8070).
// Fragments from the fragment cache must always be cloned and never used
// in place.
// 根据情况使用克隆的文档片段或原始片段的最后一个元素
results.cacheable || (l > 1 && i < lastIndex) ?
jQuery.clone(fragment, true, true) :
fragment
@ -6495,20 +6555,31 @@ var getText = Sizzle.getText = function( elem ) {
}
}
// 如果 scripts 数组的长度不为0即存在脚本元素
if (scripts.length) {
// 使用 jQuery 的 each 方法遍历 scripts 数组
jQuery.each(scripts, function (i, elem) {
// 如果当前脚本元素有 src 属性,即外部脚本
if (elem.src) {
// 使用 jQuery 的 ajax 方法异步(但这里设置为 false即同步加载外部脚本
jQuery.ajax({
type: "GET",
type: "GET", // 请求类型
global: false,
// 不触发全局 AJAX 事件处理程序
url: elem.src,
// 请求的 URL
async: false,
// 强制同步请求
dataType: "script"
// 预期服务器返回的数据类型
});
} else {
// 如果脚本是内联的,则直接执行
jQuery.globalEval((elem.text || elem.textContent || elem.innerHTML || "").replace(rcleanScript, "/*$0*/"));
// 注意rcleanScript 未在代码段中定义,可能是用于清理脚本内容的正则表达式
}
// 如果脚本元素有父节点,则从 DOM 中移除该脚本元素
if (elem.parentNode) {
elem.parentNode.removeChild(elem);
}
@ -6516,102 +6587,109 @@ var getText = Sizzle.getText = function( elem ) {
}
}
// 返回当前 jQuery 对象,支持链式调用
return this;
}
});
// 定义一个函数,用于处理表格元素,确保操作的是 tbody 元素或为其添加一个
function root( elem, cur ) {
return jQuery.nodeName(elem, "table") ?
(elem.getElementsByTagName("tbody")[0] ||
// 如果表格有 tbody则返回第一个
elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
// 否则,为表格添加一个新的 tbody 并返回
elem;
// 如果不是表格,则直接返回元素本身
}
// 定义一个函数,用于克隆元素时复制事件和数据
function cloneCopyEvent( src, dest ) {
// 如果目标元素不是 DOM 元素或源元素没有数据,则直接返回
if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
return;
}
var type, i, l,
oldData = jQuery._data( src ),
// 获取源元素的数据
curData = jQuery._data( dest, oldData ),
// 在目标元素上设置与源元素相同的数据引用
events = oldData.events;
// 获取源元素的事件
if ( events ) {
delete curData.handle;
// 删除目标元素上的 handle 引用
curData.events = {};
// 为目标元素创建一个新的事件对象
// 遍历源元素的所有事件类型
for ( type in events ) {
for ( i = 0, l = events[ type ].length; i < l; i++ ) {
// 将事件添加到目标元素
jQuery.event.add( dest, type, events[ type ][ i ] );
}
}
}
// make the cloned public data object a copy from the original
// 如果目标元素有数据,则复制这些数据
if ( curData.data ) {
curData.data = jQuery.extend( {}, curData.data );
}
}
// 定义一个函数,用于在克隆元素时修复属性
function cloneFixAttributes( src, dest ) {
var nodeName;
// We do not need to do anything for non-Elements
// 如果目标元素不是 DOM 元素,则直接返回
if ( dest.nodeType !== 1 ) {
return;
}
// clearAttributes removes the attributes, which we don't want,
// but also removes the attachEvent events, which we *do* want
// 使用 clearAttributes 清除目标元素的属性(如果存在此方法)
// 注意:这也会清除事件,但我们稍后会重新添加
if ( dest.clearAttributes ) {
dest.clearAttributes();
}
// mergeAttributes, in contrast, only merges back on the
// original attributes, not the events
// 使用 mergeAttributes 合并源元素的属性到目标元素(如果存在此方法)
if ( dest.mergeAttributes ) {
dest.mergeAttributes( src );
}
// 获取目标元素的节点名称(小写)
nodeName = dest.nodeName.toLowerCase();
// IE6-8 fail to clone children inside object elements that use
// the proprietary classid attribute value (rather than the type
// attribute) to identify the type of content to display
// 对于 object 元素,使用 outerHTML 来确保正确克隆
if ( nodeName === "object" ) {
dest.outerHTML = src.outerHTML;
// 对于 checkbox 和 radio确保复制 checked 状态和值
} else if ( nodeName === "input" && (src.type === "checkbox" || src.type === "radio") ) {
// IE6-8 fails to persist the checked state of a cloned checkbox
// or radio button. Worse, IE6-7 fail to give the cloned element
// a checked appearance if the defaultChecked value isn't also set
if ( src.checked ) {
dest.defaultChecked = dest.checked = src.checked;
}
// IE6-7 get confused and end up setting the value of a cloned
// checkbox/radio button to an empty string instead of "on"
if ( dest.value !== src.value ) {
dest.value = src.value;
}
// IE6-8 fails to return the selected option to the default selected
// state when cloning options
// 对于 option 元素,确保复制 selected 状态
} else if ( nodeName === "option" ) {
dest.selected = src.defaultSelected;
// IE6-8 fails to set the defaultValue to the correct value when
// cloning other types of input fields
// 对于 input 和 textarea 元素,确保复制 defaultValue
} else if ( nodeName === "input" || nodeName === "textarea" ) {
dest.defaultValue = src.defaultValue;
// IE blanks contents when cloning scripts
// 对于 script 元素,确保复制文本内容
} else if ( nodeName === "script" && dest.text !== src.text ) {
dest.text = src.text;
}
// Event data gets referenced instead of copied if the expando
// gets copied too
dest.removeAttribute( jQuery.expando );

Loading…
Cancel
Save