如何在JavaScript中仅删除父元素而不删除其子元素?

101

假设:

<div>
  pre text
  <div class="remove-just-this">
    <p>child foo</p>
    <p>child bar</p>
    nested text
  </div>
  post text
</div>

转化为:

<div>
  pre text
  <p>child foo</p>
  <p>child bar</p>
  nested text
  post text
</div>

我一直在尝试使用Mootools、jQuery甚至原生JavaScript,但是都不知道如何实现这个想法。

13个回答

143

使用jQuery,您可以这样做:

var cnt = $(".remove-just-this").contents();
$(".remove-just-this").replaceWith(cnt);

文档的快速链接:


4
“cnt”的意义是什么? - Steven Lu
1
'cnt'只是一个变量名,用于保存“内容”。 - George Anderson
1
我不确定为什么,但是当我使用contents()时,这对我没有起作用。然而,当我使用html()代替contents()时,它就像魔法一样奏效了! - vertigoelectric
$('.remove-just-this').replaceWith(function() { return $(this).html(); }); - Taufik Nur Rahmanda
不要使用jQuery,现代JS支持这个node.replaceWith(...node.childNodes) - Gibolt
显示剩余2条评论

37

独立于库的方法是将要删除的元素的所有子节点插入到自身之前(这会隐式地将它们从旧位置移除),然后再将其删除:

while (nodeToBeRemoved.firstChild)
{
    nodeToBeRemoved.parentNode.insertBefore(nodeToBeRemoved.firstChild,
                                            nodeToBeRemoved);
}

nodeToBeRemoved.parentNode.removeChild(nodeToBeRemoved);

这将把所有子节点按正确顺序移动到正确的位置。


10
现代的 JavaScript 支持以下操作:node.replaceWith(...node.childNodes) - Gibolt

36

为了保留事件处理程序等内容,请确保使用DOM而不是innerHTML来完成此操作(如果使用jk提供的jQuery解决方案,请确保它移动DOM节点而不是在内部使用innerHTML)。

我的答案与insin的答案非常相似,但对于大型结构来说性能更好(逐个附加每个节点可能会对重绘产生负担,在其中必须重新应用CSS样式以进行每次appendChild调用;使用DocumentFragment,则只需要一次,因为它在添加到文档之前不会被显示出来)。

var fragment = document.createDocumentFragment();
while(element.firstChild) {
    fragment.appendChild(element.firstChild);
}
element.parentNode.replaceChild(fragment, element);

30
 $('.remove-just-this > *').unwrap()

29

更优雅的方式是

$('.remove-just-this').contents().unwrap();

3
最佳答案。谢谢。 - user706420

18

使用现代的JS!

const node = document.getElementsByClassName('.remove-just-this')[0];
node.replaceWith(...node.childNodes); // or node.children, if you don't want textNodes

oldNode.replaceWith(newNode) 是有效的 ES5 代码。

...array 是展开运算符,将每个数组元素作为参数传递。


8

使用其内容替换div:

const wrapper = document.querySelector('.remove-just-this');
wrapper.outerHTML = wrapper.innerHTML;
<div>
  pre text
  <div class="remove-just-this">
    <p>child foo</p>
    <p>child bar</p>
    nested text
  </div>
  post text
</div>


2
无论使用哪个库,您都必须在从DOM中删除外部div之前克隆内部div。然后,您必须将克隆的内部div添加到DOM中外部div所在的位置。因此,步骤如下:
  1. 将外部div的父级保存到一个变量中
  2. 将内部div复制到另一个变量中。可以通过将内部div的innerHTML保存到变量中的快速且不太规范的方式完成此操作,也可以递归节点一遍遍地复制内部树。
  3. 使用外部div作为参数,在外部div的父级上调用removeChild。
  4. 将复制的内部内容插入到正确的位置的外部div的父级中。
有些库会为您执行其中的一些或所有操作,但是类似上述的操作将在幕后进行。

2

2

我在处理一个重要的DOM时,希望找到最佳的性能答案。

eyelidlessness的回答指出,使用javascript可以获得最佳性能。

我对5000行和400,000个字符进行了以下执行时间测试,其中包含了一个复杂的DOM组合部分需要去除。为方便起见,在使用javascript时我使用了ID而不是class。

使用$.unwrap()

$('#remove-just-this').contents().unwrap();

201.237毫秒

使用$.replaceWith()

var cnt = $("#remove-just-this").contents();
$("#remove-just-this").replaceWith(cnt);

156.983毫秒

使用javascript中的DocumentFragment

var element = document.getElementById('remove-just-this');
var fragment = document.createDocumentFragment();
while(element.firstChild) {
    fragment.appendChild(element.firstChild);
}
element.parentNode.replaceChild(fragment, element);

147.211毫秒

结论

在性能方面,即使在相对较大的DOM结构上,使用jQuery和JavaScript之间的差异并不是很大。令人惊讶的是,$.unwrap()$.replaceWith()更耗费成本。 这些测试是使用jQuery 1.12.4进行的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接