深入学习jquery源码之replaceWith()和replaceAll()
replaceWith(content|fn)
概述
将所有匹配的元素替换成指定的HTML或DOM元素。
参数
content String, Element, jQuery, Function
用于将匹配元素替换掉的内容。如果这里传递一个函数进来的话,函数返回值必须是HTML字符串。
fn Function
返回THML字符串,用来替换的内容。
把所有的段落标记替换成加粗的标记。
<p>Hello</p><p>cruel</p><p>World</p>
$("p").replaceWith("<b>Paragraph. </b>");
<b>Paragraph. </b><b>Paragraph. </b><b>Paragraph. </b>
用第一段替换第三段,你可以发现他是移动到目标位置来替换,而不是复制一份来替换。
<div class="container">
<div class="inner first">Hello</div>
<div class="inner second">And</div>
<div class="inner third">Goodbye</div>
</div>
$('.third').replaceWith($('.first'));
<div class="container">
<div class="inner second">And</div>
<div class="inner first">Hello</div>
</div>
replaceAll(selector)
概述
用匹配的元素替换掉所有 selector匹配到的元素。
在jQuery 1.3.2中,appendTo, prependTo, insertBefore, insertAfter, 和 replaceAll这个几个方法成为一个破坏性操作,要选择先前选中的元素,需要使用end()方法,参见 appendTo 方法的例二。
参数
selector 选择器
用于查找所要被替换的元素
把所有的段落标记替换成加粗标记
<p>Hello</p><p>cruel</p><p>World</p>
$("<b>Paragraph. </b>").replaceAll("p");
<b>Paragraph. </b><b>Paragraph. </b><b>Paragraph. </b>
jquery源码
jQuery.each({
appendTo: "append",
prependTo: "prepend",
insertBefore: "before",
insertAfter: "after",
replaceAll: "replaceWith"
}, function (name, original) {
jQuery.fn[name] = function (selector) {
var elems,
i = 0,
ret = [],
insert = jQuery(selector),
last = insert.length - 1;
for (; i <= last; i++) {
elems = i === last ? this : this.clone(true);
jQuery(insert[i])[original](elems);
// Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get()
push.apply(ret, elems.get());
}
return this.pushStack(ret);
};
});
jQuery.fn.extend({
replaceWith: function () {
var arg = arguments[0];
// Make the changes, replacing each context element with the new content
this.domManip(arguments, function (elem) {
arg = this.parentNode;
jQuery.cleanData(getAll(this));
if (arg) {
arg.replaceChild(elem, this);
}
});
// Force removal if there was no new content (e.g., from empty arguments)
return arg && (arg.length || arg.nodeType) ? this : this.remove();
},
domManip: function (args, callback) {
// Flatten any nested arrays
args = concat.apply([], args);
var first, node, hasScripts,
scripts, doc, fragment,
i = 0,
l = this.length,
set = this,
iNoClone = l - 1,
value = args[0],
isFunction = jQuery.isFunction(value);
// We can't cloneNode fragments that contain checked, in WebKit
if (isFunction ||
(l > 1 && typeof value === "string" &&
!support.checkClone && rchecked.test(value))) {
return this.each(function (index) {
var self = set.eq(index);
if (isFunction) {
args[0] = value.call(this, index, self.html());
}
self.domManip(args, callback);
});
}
if (l) {
fragment = jQuery.buildFragment(args, this[0].ownerDocument, false, this);
first = fragment.firstChild;
if (fragment.childNodes.length === 1) {
fragment = first;
}
if (first) {
scripts = jQuery.map(getAll(fragment, "script"), disableScript);
hasScripts = scripts.length;
// Use the original fragment for the last item instead of the first because it can end up
// being emptied incorrectly in certain situations (#8070).
for (; i < l; i++) {
node = fragment;
if (i !== iNoClone) {
node = jQuery.clone(node, true, true);
// Keep references to cloned scripts for later restoration
if (hasScripts) {
jQuery.merge(scripts, getAll(node, "script"));
}
}
callback.call(this[i], node, i);
}
if (hasScripts) {
doc = scripts[scripts.length - 1].ownerDocument;
// Reenable scripts
jQuery.map(scripts, restoreScript);
// Evaluate executable scripts on first document insertion
for (i = 0; i < hasScripts; i++) {
node = scripts[i];
if (rscriptType.test(node.type || "") &&
!jQuery._data(node, "globalEval") && jQuery.contains(doc, node)) {
if (node.src) {
// Optional AJAX dependency, but won't run scripts if not present
if (jQuery._evalUrl) {
jQuery._evalUrl(node.src);
}
} else {
jQuery.globalEval((node.text || node.textContent || node.innerHTML || "").replace(rcleanScript, ""));
}
}
}
}
// Fix #11809: Avoid leaking memory
fragment = first = null;
}
}
return this;
}
});