如何在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专用的答案,会有额外的加分。


当前回答

通过Javascript删除节点的子节点的最简单方法

var myNode = document.getElementById("foo");
while(myNode.hasChildNodes())
{
   myNode.removeChild(myNode.lastChild);
}

其他回答

 let el = document.querySelector('#el');
 if (el.hasChildNodes()) {
      el.childNodes.forEach(child => el.removeChild(child));
 }

选项1 A:清除innerHTML。

这种方法很简单,但可能不适合高性能应用程序,因为它调用浏览器的HTML解析器(尽管浏览器可能针对值为空字符串的情况进行优化)。

doFoo。Onclick = () => { const myNode = document.getElementById("foo"); myNode。innerHTML = "; } <div id='foo' style="height: 100px;宽度:100 px;边框:1px纯黑色;" > < span >你好> < /跨度 < / div > <button id='doFoo'>通过innerHTML删除</button>

选项1 B:清除文本内容

如上所述,但是使用. textcontent。根据MDN,这将比innerHTML更快,因为浏览器不会调用他们的HTML解析器,而是立即用单个#text节点替换元素的所有子元素。

doFoo。Onclick = () => { const myNode = document.getElementById("foo"); myNode。textContent = "; } <div id='foo' style="height: 100px;宽度:100 px;边框:1px纯黑色;" > < span >你好> < /跨度 < / div > <按钮id='doFoo'>删除通过textContent</按钮>

选项2 A:循环删除每个lastChild:

这个答案的早期编辑使用了firstChild,但在计算机科学中更新为使用lastChild,一般来说,删除集合的最后一个元素比删除第一个元素要快得多(这取决于集合是如何实现的)。 循环继续检查firstChild,以防检查firstChild比检查lastChild快(例如,如果元素列表被UA实现为有向链表)。

doFoo。Onclick = () => { const myNode = document.getElementById("foo"); while (myNode.firstChild) { myNode.removeChild (myNode.lastChild); } } <div id='foo' style="height: 100px;宽度:100 px;边框:1px纯黑色;" > < span >你好> < /跨度 < / div > <button id='doFoo'>通过lastChild-loop删除</button>

选项2 B:循环删除每个lastElementChild:

这种方法保留了所有非element(即#text节点和<!)——comments——>)父类的子类(但不是它们的后代)——这可能在你的应用程序中是可取的(例如,一些模板系统使用内联HTML注释来存储模板指令)。 这种方法直到最近几年才被使用,因为Internet Explorer只在IE9中添加了对lastElementChild的支持。

doFoo。Onclick = () => { const myNode = document.getElementById("foo"); while (myNode.lastElementChild) { myNode.removeChild (myNode.lastElementChild); } } <div id='foo' style="height: 100px;宽度:100 px;边框:1px纯黑色;" > <!——这条评论不会被删除——> < span > <你好!-></span> . -></span> . - <!——但这只不会。--> < / div > <button id='doFoo'>通过lastElementChild-loop删除</button>

好处:元素。clearChildren monkey-patch:

我们可以在JavaScript中的Element原型中添加一个新的method-property,以简化对它的调用,只调用el. clearchildren()(其中el是任何HTML元素对象)。 (严格地说,这是一个猴子补丁,而不是一个polyfill,因为这不是一个标准的DOM特性或缺失的特性。请注意,在许多情况下,不鼓励打猴子补丁。)

if( typeof Element.prototype.clearChildren === 'undefined' ) { Object.defineProperty(Element.prototype, 'clearChildren', { configurable: true, enumerable: false, value: function() { while(this.firstChild) this.removeChild(this.lastChild); } }); } <div id='foo' style="height: 100px; width: 100px; border: 1px solid black;"> <span>Hello <!-- This comment WILL be removed --></span> </div> <button onclick="this.previousElementSibling.clearChildren()">Remove via monkey-patch</button>

jQuery的其他方法

var foo = $("#foo");
foo.children().remove();
//or
$("*", foo ).remove();
//or
foo.html("");
//or
foo.empty();

Ecma6使它简单而紧凑

myNode.querySelectorAll('*').forEach( n => n.remove() );

这回答了问题,并删除了“所有子节点”。

如果有属于myNode的文本节点,它们不能被CSS选择器选中,在这种情况下,我们必须应用(also):

myNode.textContent = '';

实际上,最后一个可能是最快和更有效的解决方案。

.textContent比.innerText和.innerHTML更有效,参见:MDN

以下是我通常做的事情:

HTMLElement.prototype.empty = function() {
    while (this.firstChild) {
        this.removeChild(this.firstChild);
    }
}

瞧,之后你可以清空任何dom元素:

anyDom.empty()