|
|
|
@ -6188,429 +6188,507 @@ var getText = Sizzle.getText = function( elem ) {
|
|
|
|
|
// 扩展jQuery的fn对象,添加一些新的方法
|
|
|
|
|
jQuery.fn.extend({
|
|
|
|
|
// 设置或获取匹配元素的文本内容
|
|
|
|
|
text: function( value ) {
|
|
|
|
|
return jQuery.access( this, function( value ) {
|
|
|
|
|
text: function (value) {
|
|
|
|
|
return jQuery.access(this, function (value) {
|
|
|
|
|
return value === undefined ?
|
|
|
|
|
jQuery.text( this ) :
|
|
|
|
|
this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
|
|
|
|
|
}, null, value, arguments.length );
|
|
|
|
|
jQuery.text(this) :
|
|
|
|
|
this.empty().append((this[0] && this[0].ownerDocument || document).createTextNode(value));
|
|
|
|
|
}, null, value, arguments.length);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 将所有匹配元素包裹在一个HTML结构中
|
|
|
|
|
wrapAll: function( html ) {
|
|
|
|
|
if ( jQuery.isFunction( html ) ) {
|
|
|
|
|
return this.each(function(i) {
|
|
|
|
|
jQuery(this).wrapAll( html.call(this, i) );
|
|
|
|
|
wrapAll: function (html) {
|
|
|
|
|
if (jQuery.isFunction(html)) {
|
|
|
|
|
return this.each(function (i) {
|
|
|
|
|
jQuery(this).wrapAll(html.call(this, i));
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( this[0] ) {
|
|
|
|
|
if (this[0]) {
|
|
|
|
|
// 克隆html结构并插入到DOM中
|
|
|
|
|
var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
|
|
|
|
|
var wrap = jQuery(html, this[0].ownerDocument).eq(0).clone(true);
|
|
|
|
|
|
|
|
|
|
if ( this[0].parentNode ) {
|
|
|
|
|
wrap.insertBefore( this[0] );
|
|
|
|
|
if (this[0].parentNode) {
|
|
|
|
|
wrap.insertBefore(this[0]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 将匹配元素插入到克隆的html结构中
|
|
|
|
|
wrap.map(function() {
|
|
|
|
|
wrap.map(function () {
|
|
|
|
|
var elem = this;
|
|
|
|
|
|
|
|
|
|
while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
|
|
|
|
|
while (elem.firstChild && elem.firstChild.nodeType === 1) {
|
|
|
|
|
elem = elem.firstChild;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return elem;
|
|
|
|
|
}).append( this );
|
|
|
|
|
}).append(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return this;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 将匹配元素的内部内容包裹在一个HTML结构中
|
|
|
|
|
wrapInner: function( html ) {
|
|
|
|
|
if ( jQuery.isFunction( html ) ) {
|
|
|
|
|
return this.each(function(i) {
|
|
|
|
|
jQuery(this).wrapInner( html.call(this, i) );
|
|
|
|
|
wrapInner: function (html) {
|
|
|
|
|
if (jQuery.isFunction(html)) {
|
|
|
|
|
return this.each(function (i) {
|
|
|
|
|
jQuery(this).wrapInner(html.call(this, i));
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return this.each(function() {
|
|
|
|
|
var self = jQuery( this ),
|
|
|
|
|
return this.each(function () {
|
|
|
|
|
var self = jQuery(this),
|
|
|
|
|
contents = self.contents();
|
|
|
|
|
|
|
|
|
|
if ( contents.length ) {
|
|
|
|
|
if (contents.length) {
|
|
|
|
|
// 如果元素有子节点,则将子节点包裹在html结构中
|
|
|
|
|
contents.wrapAll( html );
|
|
|
|
|
contents.wrapAll(html);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
// 如果没有子节点,则直接追加html
|
|
|
|
|
self.append( html );
|
|
|
|
|
self.append(html);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 将每个匹配元素包裹在一个HTML结构中
|
|
|
|
|
wrap: function( html ) {
|
|
|
|
|
var isFunction = jQuery.isFunction( html );
|
|
|
|
|
wrap: function (html) {
|
|
|
|
|
var isFunction = jQuery.isFunction(html);
|
|
|
|
|
|
|
|
|
|
return this.each(function(i) {
|
|
|
|
|
return this.each(function (i) {
|
|
|
|
|
// 对每个元素执行包装操作,如果html是函数,则传入当前元素的索引并调用函数
|
|
|
|
|
jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
|
|
|
|
|
jQuery(this).wrapAll(isFunction ? html.call(this, i) : html);
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 移除匹配元素的父元素,但保留元素本身及其子元素
|
|
|
|
|
unwrap: function() {
|
|
|
|
|
return this.parent().each(function() {
|
|
|
|
|
if ( !jQuery.nodeName( this, "body" ) ) {
|
|
|
|
|
unwrap: function () {
|
|
|
|
|
return this.parent().each(function () {
|
|
|
|
|
if (!jQuery.nodeName(this, "body")) {
|
|
|
|
|
// 如果不是body元素,则用其子节点替换该元素
|
|
|
|
|
jQuery( this ).replaceWith( this.childNodes );
|
|
|
|
|
jQuery(this).replaceWith(this.childNodes);
|
|
|
|
|
}
|
|
|
|
|
}).end();
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 在匹配元素的末尾追加内容
|
|
|
|
|
append: function() {
|
|
|
|
|
return this.domManip(arguments, true, function( elem ) {
|
|
|
|
|
if ( this.nodeType === 1 ) {
|
|
|
|
|
this.appendChild( elem );
|
|
|
|
|
append: function () {
|
|
|
|
|
return this.domManip(arguments, true, function (elem) {
|
|
|
|
|
if (this.nodeType === 1) {
|
|
|
|
|
this.appendChild(elem);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 在匹配元素的前面追加内容
|
|
|
|
|
prepend: function() {
|
|
|
|
|
return this.domManip(arguments, true, function( elem ) {
|
|
|
|
|
if ( this.nodeType === 1 ) {
|
|
|
|
|
this.insertBefore( elem, this.firstChild );
|
|
|
|
|
prepend: function () {
|
|
|
|
|
return this.domManip(arguments, true, function (elem) {
|
|
|
|
|
if (this.nodeType === 1) {
|
|
|
|
|
this.insertBefore(elem, this.firstChild);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
before: function() {
|
|
|
|
|
if ( this[0] && this[0].parentNode ) {
|
|
|
|
|
return this.domManip(arguments, false, function( elem ) {
|
|
|
|
|
this.parentNode.insertBefore( elem, this );
|
|
|
|
|
});
|
|
|
|
|
} else if ( arguments.length ) {
|
|
|
|
|
var set = jQuery.clean( arguments );
|
|
|
|
|
set.push.apply( set, this.toArray() );
|
|
|
|
|
return this.pushStack( set, "before", arguments );
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
// 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) { // 如果有参数传入
|
|
|
|
|
// 清理参数,将它们转换成一个jQuery对象数组
|
|
|
|
|
var set = jQuery.clean(arguments);
|
|
|
|
|
// 将当前jQuery对象中的元素添加到set数组末尾
|
|
|
|
|
set.push.apply(set, this.toArray());
|
|
|
|
|
// 返回一个新的jQuery对象,包含set数组中的元素
|
|
|
|
|
return this.pushStack(set, "before", arguments);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
after: function() {
|
|
|
|
|
if ( this[0] && this[0].parentNode ) {
|
|
|
|
|
return this.domManip(arguments, false, function( elem ) {
|
|
|
|
|
this.parentNode.insertBefore( elem, this.nextSibling );
|
|
|
|
|
});
|
|
|
|
|
} else if ( arguments.length ) {
|
|
|
|
|
var set = this.pushStack( this, "after", arguments );
|
|
|
|
|
set.push.apply( set, jQuery.clean(arguments) );
|
|
|
|
|
return set;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
// 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) { // 如果有参数传入
|
|
|
|
|
// 创建一个新的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: function( selector, keepData ) {
|
|
|
|
|
for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
|
|
|
|
|
if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
|
|
|
|
|
if ( !keepData && elem.nodeType === 1 ) {
|
|
|
|
|
jQuery.cleanData( elem.getElementsByTagName("*") );
|
|
|
|
|
jQuery.cleanData( [ elem ] );
|
|
|
|
|
}
|
|
|
|
|
// 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 );
|
|
|
|
|
// 如果元素有父节点,则从父节点中移除该元素
|
|
|
|
|
if (elem.parentNode) {
|
|
|
|
|
elem.parentNode.removeChild(elem);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return this;
|
|
|
|
|
},
|
|
|
|
|
// 返回当前jQuery对象
|
|
|
|
|
return this;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
empty: function() {
|
|
|
|
|
for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
|
|
|
|
|
// Remove element nodes and prevent memory leaks
|
|
|
|
|
if ( elem.nodeType === 1 ) {
|
|
|
|
|
jQuery.cleanData( elem.getElementsByTagName("*") );
|
|
|
|
|
}
|
|
|
|
|
// empty方法:移除当前元素的所有子元素
|
|
|
|
|
empty: function () {
|
|
|
|
|
// 遍历当前jQuery对象中的每个元素
|
|
|
|
|
for (var i = 0, elem; (elem = this[i]) != null; i++) {
|
|
|
|
|
// 如果元素是DOM元素
|
|
|
|
|
if (elem.nodeType === 1) {
|
|
|
|
|
// 清理元素上的所有子元素的数据
|
|
|
|
|
jQuery.cleanData(elem.getElementsByTagName("*"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Remove any remaining nodes
|
|
|
|
|
while ( elem.firstChild ) {
|
|
|
|
|
elem.removeChild( elem.firstChild );
|
|
|
|
|
// 移除元素的所有子节点
|
|
|
|
|
while (elem.firstChild) {
|
|
|
|
|
elem.removeChild(elem.firstChild);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return this;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
clone: function( dataAndEvents, deepDataAndEvents ) {
|
|
|
|
|
dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
|
|
|
|
|
deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
|
|
|
|
|
// 返回当前jQuery对象
|
|
|
|
|
return this;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
return this.map( function () {
|
|
|
|
|
return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
// clone方法:克隆当前元素
|
|
|
|
|
clone: function (dataAndEvents, deepDataAndEvents) {
|
|
|
|
|
// 设置dataAndEvents和deepDataAndEvents的默认值
|
|
|
|
|
dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
|
|
|
|
|
deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
|
|
|
|
|
|
|
|
|
|
html: function( value ) {
|
|
|
|
|
return jQuery.access( this, function( value ) {
|
|
|
|
|
var elem = this[0] || {},
|
|
|
|
|
i = 0,
|
|
|
|
|
l = this.length;
|
|
|
|
|
// 返回一个新的jQuery对象,包含当前元素的克隆
|
|
|
|
|
return this.map(function () {
|
|
|
|
|
return jQuery.clone(this, dataAndEvents, deepDataAndEvents);
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
if ( value === undefined ) {
|
|
|
|
|
return elem.nodeType === 1 ?
|
|
|
|
|
elem.innerHTML.replace( rinlinejQuery, "" ) :
|
|
|
|
|
null;
|
|
|
|
|
}
|
|
|
|
|
// 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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
|
|
|
|
|
( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
|
|
|
|
|
!wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) {
|
|
|
|
|
// 如果value是字符串,并且满足特定条件(不触发innerHTML的bug)
|
|
|
|
|
if (typeof value === "string" && !rnoInnerhtml.test(value) &&
|
|
|
|
|
(jQuery.support.leadingWhitespace || !rleadingWhitespace.test(value)) &&
|
|
|
|
|
!wrapMap[(rtagName.exec(value) || ["", ""])[1].toLowerCase()]) {
|
|
|
|
|
|
|
|
|
|
value = value.replace( rxhtmlTag, "<$1></$2>" );
|
|
|
|
|
// 尝试直接设置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 ) {
|
|
|
|
|
jQuery.cleanData( elem.getElementsByTagName( "*" ) );
|
|
|
|
|
elem.innerHTML = value;
|
|
|
|
|
try {
|
|
|
|
|
for (; i < l; i++) {
|
|
|
|
|
elem = this[i] || {};
|
|
|
|
|
// 获取当前元素
|
|
|
|
|
if (elem.nodeType === 1) {
|
|
|
|
|
// 如果元素是DOM元素
|
|
|
|
|
jQuery.cleanData(elem.getElementsByTagName("*"));
|
|
|
|
|
// 清理数据
|
|
|
|
|
elem.innerHTML = value;
|
|
|
|
|
// 设置innerHTML
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
elem = 0;
|
|
|
|
|
// 重置elem
|
|
|
|
|
|
|
|
|
|
// 如果使用innerHTML失败,则使用备用方法
|
|
|
|
|
} catch (e) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
elem = 0;
|
|
|
|
|
// 如果value值存在,则清空当前元素的内容并追加value值
|
|
|
|
|
if (elem) {
|
|
|
|
|
this.empty().append(value);
|
|
|
|
|
}
|
|
|
|
|
}, null, value, arguments.length);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// If using innerHTML throws an exception, use the fallback method
|
|
|
|
|
} catch(e) {}
|
|
|
|
|
}
|
|
|
|
|
// 定义一个 replaceWith 方法,用于替换当前匹配的元素集合
|
|
|
|
|
replaceWith: function (value) {
|
|
|
|
|
// 确保至少有一个元素且该元素有父节点
|
|
|
|
|
if (this[0] && this[0].parentNode) {
|
|
|
|
|
// 如果传入的值是一个函数,则对每个匹配的元素执行此函数,并替换元素
|
|
|
|
|
if (jQuery.isFunction(value)) {
|
|
|
|
|
return this.each(function (i) {
|
|
|
|
|
var self = jQuery(this), old = self.html();
|
|
|
|
|
// 获取当前元素并保存其HTML内容
|
|
|
|
|
self.replaceWith(value.call(this, i, old));
|
|
|
|
|
// 调用函数并替换当前元素
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( elem ) {
|
|
|
|
|
this.empty().append( value );
|
|
|
|
|
// 如果传入的值不是字符串,则将其转换为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) : // 如果传入值是一个函数,则执行它并返回结果;否则直接返回jQuery对象
|
|
|
|
|
this; // 如果没有匹配的元素,则直接返回当前jQuery对象
|
|
|
|
|
}
|
|
|
|
|
}, null, value, arguments.length );
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 定义一个 detach 方法,用于从DOM中分离元素
|
|
|
|
|
detach: function (selector) {
|
|
|
|
|
return this.remove(selector, true);
|
|
|
|
|
// 调用 remove 方法并设置第二个参数为 true 以实现分离而非删除
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
self.replaceWith( value.call( this, i, old ) );
|
|
|
|
|
// 定义一个 domManip 方法,用于在DOM中进行复杂的操作(如插入、删除、替换等)
|
|
|
|
|
domManip: function (args, table, callback) {
|
|
|
|
|
var results, first, fragment, parent,
|
|
|
|
|
value = args[0],
|
|
|
|
|
// 获取传入的操作值
|
|
|
|
|
scripts = [];
|
|
|
|
|
// 用于存储脚本元素的数组
|
|
|
|
|
|
|
|
|
|
// 如果不支持复选框的克隆,并且传入的值是字符串且包含复选框,则对每个元素单独处理
|
|
|
|
|
if (!jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test(value)) {
|
|
|
|
|
return this.each(function () {
|
|
|
|
|
jQuery(this).domManip(args, table, callback, true);
|
|
|
|
|
// 递归调用并设置额外的参数
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( typeof value !== "string" ) {
|
|
|
|
|
value = jQuery( value ).detach();
|
|
|
|
|
// 如果传入的值是一个函数,则对每个匹配的元素执行此函数,并传入参数进行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); // 递归调用 domManip 方法
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return this.each(function() {
|
|
|
|
|
var next = this.nextSibling,
|
|
|
|
|
parent = this.parentNode;
|
|
|
|
|
// 确保有至少一个匹配的元素
|
|
|
|
|
if (this[0]) {
|
|
|
|
|
parent = value && value.parentNode;
|
|
|
|
|
// 获取传入值的父节点
|
|
|
|
|
|
|
|
|
|
jQuery( this ).remove();
|
|
|
|
|
// 如果传入的值是一个文档片段且其子节点数量与当前匹配的元素数量相同,则直接使用该片段
|
|
|
|
|
if (jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length) {
|
|
|
|
|
results = {fragment: parent}; // 设置结果对象,包含文档片段
|
|
|
|
|
|
|
|
|
|
if ( next ) {
|
|
|
|
|
jQuery(next).before( value );
|
|
|
|
|
} else {
|
|
|
|
|
jQuery(parent).append( value );
|
|
|
|
|
// 否则,根据传入的值和当前匹配的元素创建一个新的文档片段
|
|
|
|
|
results = jQuery.buildFragment(args, this, scripts);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
return this.length ?
|
|
|
|
|
this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
|
|
|
|
|
this;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
detach: function( selector ) {
|
|
|
|
|
return this.remove( selector, true );
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
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 );
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 );
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
fragment = results.fragment; // 获取文档片段
|
|
|
|
|
|
|
|
|
|
if ( this[0] ) {
|
|
|
|
|
parent = value && value.parentNode;
|
|
|
|
|
// 如果文档片段只有一个子节点,则直接使用该子节点
|
|
|
|
|
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],
|
|
|
|
|
// 根据情况使用克隆的文档片段或原始片段的最后一个元素
|
|
|
|
|
results.cacheable || (l > 1 && i < lastIndex) ?
|
|
|
|
|
jQuery.clone(fragment, true, true) :
|
|
|
|
|
fragment
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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 };
|
|
|
|
|
// 如果 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", // 请求类型
|
|
|
|
|
global: false,
|
|
|
|
|
// 不触发全局 AJAX 事件处理程序
|
|
|
|
|
url: elem.src,
|
|
|
|
|
// 请求的 URL
|
|
|
|
|
async: false,
|
|
|
|
|
// 强制同步请求
|
|
|
|
|
dataType: "script"
|
|
|
|
|
// 预期服务器返回的数据类型
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
// 如果脚本是内联的,则直接执行
|
|
|
|
|
jQuery.globalEval((elem.text || elem.textContent || elem.innerHTML || "").replace(rcleanScript, "/*$0*/"));
|
|
|
|
|
// 注意:rcleanScript 未在代码段中定义,可能是用于清理脚本内容的正则表达式
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
results = jQuery.buildFragment( args, this, scripts );
|
|
|
|
|
// 如果脚本元素有父节点,则从 DOM 中移除该脚本元素
|
|
|
|
|
if (elem.parentNode) {
|
|
|
|
|
elem.parentNode.removeChild(elem);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( scripts.length ) {
|
|
|
|
|
jQuery.each( scripts, function( i, elem ) {
|
|
|
|
|
if ( elem.src ) {
|
|
|
|
|
jQuery.ajax({
|
|
|
|
|
type: "GET",
|
|
|
|
|
global: false,
|
|
|
|
|
url: elem.src,
|
|
|
|
|
async: false,
|
|
|
|
|
dataType: "script"
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "/*$0*/" ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( elem.parentNode ) {
|
|
|
|
|
elem.parentNode.removeChild( elem );
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
// 返回当前 jQuery 对象,支持链式调用
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
function root( elem, cur ) {
|
|
|
|
|
return jQuery.nodeName(elem, "table") ?
|
|
|
|
|
(elem.getElementsByTagName("tbody")[0] ||
|
|
|
|
|
elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
|
|
|
|
|
elem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function cloneCopyEvent( src, dest ) {
|
|
|
|
|
// 定义一个函数,用于处理表格元素,确保操作的是 tbody 元素或为其添加一个
|
|
|
|
|
function root( elem, cur ) {
|
|
|
|
|
return jQuery.nodeName(elem, "table") ?
|
|
|
|
|
(elem.getElementsByTagName("tbody")[0] ||
|
|
|
|
|
// 如果表格有 tbody,则返回第一个
|
|
|
|
|
elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
|
|
|
|
|
// 否则,为表格添加一个新的 tbody 并返回
|
|
|
|
|
elem;
|
|
|
|
|
// 如果不是表格,则直接返回元素本身
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// 定义一个函数,用于克隆元素时复制事件和数据
|
|
|
|
|
function cloneCopyEvent( src, dest ) {
|
|
|
|
|
|
|
|
|
|
var type, i, l,
|
|
|
|
|
oldData = jQuery._data( src ),
|
|
|
|
|
curData = jQuery._data( dest, oldData ),
|
|
|
|
|
events = oldData.events;
|
|
|
|
|
// 如果目标元素不是 DOM 元素或源元素没有数据,则直接返回
|
|
|
|
|
if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( events ) {
|
|
|
|
|
delete curData.handle;
|
|
|
|
|
curData.events = {};
|
|
|
|
|
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 ] );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for ( type in events ) {
|
|
|
|
|
for ( i = 0, l = events[ type ].length; i < l; i++ ) {
|
|
|
|
|
jQuery.event.add( dest, type, events[ type ][ i ] );
|
|
|
|
|
// 如果目标元素有数据,则复制这些数据
|
|
|
|
|
if ( curData.data ) {
|
|
|
|
|
curData.data = jQuery.extend( {}, curData.data );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
// 定义一个函数,用于在克隆元素时修复属性
|
|
|
|
|
function cloneFixAttributes( src, dest ) {
|
|
|
|
|
var nodeName;
|
|
|
|
|
|
|
|
|
|
// We do not need to do anything for non-Elements
|
|
|
|
|
if ( dest.nodeType !== 1 ) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// 如果目标元素不是 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
|
|
|
|
|
if ( dest.clearAttributes ) {
|
|
|
|
|
dest.clearAttributes();
|
|
|
|
|
}
|
|
|
|
|
// 使用 clearAttributes 清除目标元素的属性(如果存在此方法)
|
|
|
|
|
// 注意:这也会清除事件,但我们稍后会重新添加
|
|
|
|
|
if ( dest.clearAttributes ) {
|
|
|
|
|
dest.clearAttributes();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// mergeAttributes, in contrast, only merges back on the
|
|
|
|
|
// original attributes, not the events
|
|
|
|
|
if ( dest.mergeAttributes ) {
|
|
|
|
|
dest.mergeAttributes( src );
|
|
|
|
|
}
|
|
|
|
|
// 使用 mergeAttributes 合并源元素的属性到目标元素(如果存在此方法)
|
|
|
|
|
if ( dest.mergeAttributes ) {
|
|
|
|
|
dest.mergeAttributes( src );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nodeName = dest.nodeName.toLowerCase();
|
|
|
|
|
// 获取目标元素的节点名称(小写)
|
|
|
|
|
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
|
|
|
|
|
if ( nodeName === "object" ) {
|
|
|
|
|
dest.outerHTML = src.outerHTML;
|
|
|
|
|
// 对于 object 元素,使用 outerHTML 来确保正确克隆
|
|
|
|
|
if ( nodeName === "object" ) {
|
|
|
|
|
dest.outerHTML = src.outerHTML;
|
|
|
|
|
|
|
|
|
|
} 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;
|
|
|
|
|
}
|
|
|
|
|
// 对于 checkbox 和 radio,确保复制 checked 状态和值
|
|
|
|
|
} else if ( nodeName === "input" && (src.type === "checkbox" || src.type === "radio") ) {
|
|
|
|
|
if ( src.checked ) {
|
|
|
|
|
dest.defaultChecked = dest.checked = src.checked;
|
|
|
|
|
}
|
|
|
|
|
if ( dest.value !== src.value ) {
|
|
|
|
|
dest.value = src.value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
}
|
|
|
|
|
// 对于 option 元素,确保复制 selected 状态
|
|
|
|
|
} else if ( nodeName === "option" ) {
|
|
|
|
|
dest.selected = src.defaultSelected;
|
|
|
|
|
|
|
|
|
|
// IE6-8 fails to return the selected option to the default selected
|
|
|
|
|
// state when cloning options
|
|
|
|
|
} else if ( nodeName === "option" ) {
|
|
|
|
|
dest.selected = src.defaultSelected;
|
|
|
|
|
// 对于 input 和 textarea 元素,确保复制 defaultValue
|
|
|
|
|
} else if ( nodeName === "input" || nodeName === "textarea" ) {
|
|
|
|
|
dest.defaultValue = src.defaultValue;
|
|
|
|
|
|
|
|
|
|
// IE6-8 fails to set the defaultValue to the correct value when
|
|
|
|
|
// cloning other types of input fields
|
|
|
|
|
} else if ( nodeName === "input" || nodeName === "textarea" ) {
|
|
|
|
|
dest.defaultValue = src.defaultValue;
|
|
|
|
|
// 对于 script 元素,确保复制文本内容
|
|
|
|
|
} else if ( nodeName === "script" && dest.text !== src.text ) {
|
|
|
|
|
dest.text = src.text;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// IE blanks contents when cloning scripts
|
|
|
|
|
} 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
|
|
|
|
|