如何在JavaScript中删除DOM节点的所有子元素?
假设我有以下(丑陋的)HTML:
<p id="foo">
<span>hello</span>
<div>world</div>
</p>
然后我像这样获取我想要的节点
var myNode = document.getElementById("foo");
我怎么能删除foo的孩子,这样就<p id="foo"></p>是剩下的?
我能不能这样做:
myNode.childNodes = new Array();
或者我应该使用一些组合的removeElement?
我希望答案是直接的DOM;不过,如果你在jQuery中提供了一个dom专用的答案,会有额外的加分。
元素。innerHTML = ""(或.textContent)是目前为止最快的解决方案
这里的大多数答案都是基于有缺陷的测试
例如:
https://jsperf.com/innerhtml-vs-removechild/15
该测试不会在每次迭代之间向元素添加新的子元素。第一次迭代将删除元素的内容,然后每一次迭代都不执行任何操作。
在这种情况下,while (box. lastchild) box. removecchild (box. lastchild)更快,因为box. lastchild。lastChild在99%的情况下为null
这里有一个合适的测试:https://jsperf.com/innerhtml-conspiracy
最后,不要使用node. parentnode . replacechild (node. clonenode (false), node)。这将用节点本身的副本替换它的子节点。但是,这不会保留事件侦听器,并破坏对该节点的任何其他引用。
2022年+,用替代品!
现在可以使用(跨浏览器支持的)replaceChildren API替换所有的子程序:
container.replaceChildren(...arrayOfNewChildren);
这可以做到这两点:
删除所有现有的子节点,和
在一个操作中追加所有给定的新子节点。
你也可以使用相同的API来删除现有的子节点,而不替换它们:
container.replaceChildren();
这在Chrome/Edge 86+, Firefox 78+和Safari 14+中完全支持。它是完全指定的行为。这可能比这里提出的任何其他方法都要快,因为删除旧的子元素和添加新的子元素不需要innerHTML,而且是一步完成的,而不是多个步骤。
我是这样做的
data = {
"messages": [
[0, "userName", "message test"],
[1, "userName1", "message test1"]
]
}
for (let i = 0; i < data.messages.length; i++) {
var messageData = document.createElement('span')
messageData.className = 'messageClass'
messageData.innerHTML = `${data.messages[i][2]} ${'<br />'}`
$(".messages").append(messageData)
}
$('#removeMessages').on('click', () => {
node = $('.messages').get(0)
while (node.firstChild) {
node.firstChild.remove()
}
$('#removeMessages').toggle(500)
$('#addMessages').toggle(500)
})
$('#addMessages').on('click', () => {
for (let i = 0; i < data.messages.length; i++) {
var messageData = document.createElement('span')
messageData.className = 'messageClass'
messageData.innerHTML = `${data.messages[i][2]} ${'<br />'}`
$(".messages").append(messageData)
}
$('#addMessages').toggle(500)
$('#removeMessages').toggle(500)
})
#addMessages{
display:none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<div class="messages"></div>
<button type='button' id="removeMessages">Remove</button>
<button type='button' id="addMessages">Add MEssages</button>
作为对DanMan, Maarten和Matt的回应。克隆一个节点,以设置文本确实是一个可行的方法,在我的结果。
// @param {node} node
// @return {node} empty node
function removeAllChildrenFromNode (node) {
var shell;
// do not copy the contents
shell = node.cloneNode(false);
if (node.parentNode) {
node.parentNode.replaceChild(shell, node);
}
return shell;
}
// use as such
var myNode = document.getElementById('foo');
myNode = removeAllChildrenFromNode( myNode );
这也适用于不在dom中的节点,当试图访问parentNode时返回null。此外,如果您需要在添加内容之前确保节点是空的,这是非常有用的。考虑下面的用例。
// @param {node} node
// @param {string|html} content
// @return {node} node with content only
function refreshContent (node, content) {
var shell;
// do not copy the contents
shell = node.cloneNode(false);
// use innerHTML or you preffered method
// depending on what you need
shell.innerHTML( content );
if (node.parentNode) {
node.parentNode.replaceChild(shell, node);
}
return shell;
}
// use as such
var myNode = document.getElementById('foo');
myNode = refreshContent( myNode );
我发现这个方法在替换元素中的字符串时非常有用,如果你不确定节点将包含什么,与其担心如何清理混乱,不如从头开始。