在 JavaScript 中删除 DOM 节点的所有子元素

Remove all child elements of a DOM node in JavaScript

提问人:DigitalZebra 提问时间:10/18/2010 最后编辑:Benjamin LoisonDigitalZebra 更新时间:4/20/2023 访问量:1517624

问:

我将如何删除 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 DOM

评论


答:

2289赞 Gabriel McAdams 10/18/2010 #1

选项 1 A:清算。innerHTML

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

doFoo.onclick = () => {
  const myNode = document.getElementById("foo");
  myNode.innerHTML = '';
}
<div id='foo' style="height: 100px; width: 100px; border: 1px solid black;">
  <span>Hello</span>
</div>
<button id='doFoo'>Remove via innerHTML</button>

选项 1 B:清算textContent

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

doFoo.onclick = () => {
  const myNode = document.getElementById("foo");
  myNode.textContent = '';
}
<div id='foo' style="height: 100px; width: 100px; border: 1px solid black;">
  <span>Hello</span>
</div>
<button id='doFoo'>Remove via textContent</button>

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

  • 使用过此答案的早期编辑,但已更新为在计算机科学中使用,一般来说,删除集合的最后一个元素比删除第一个元素要快得多(取决于集合的实现方式)。firstChildlastChild
  • 循环继续检查,以防万一检查速度比更快(例如,如果元素列表是由 UA 实现为有向链接列表的)。firstChildfirstChildlastChild

doFoo.onclick = () => {
  const myNode = document.getElementById("foo");
  while (myNode.firstChild) {
    myNode.removeChild(myNode.lastChild);
  }
}
<div id='foo' style="height: 100px; width: 100px; border: 1px solid black;">
  <span>Hello</span>
</div>
<button id='doFoo'>Remove via lastChild-loop</button>

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

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

doFoo.onclick = () => {
  const myNode = document.getElementById("foo");
  while (myNode.lastElementChild) {
    myNode.removeChild(myNode.lastElementChild);
  }
}
<div id='foo' style="height: 100px; width: 100px; border: 1px solid black;">
  <!-- This comment won't be removed -->
  <span>Hello <!-- This comment WILL be removed --></span>
  <!-- But this one won't. -->
</div>
<button id='doFoo'>Remove via lastElementChild-loop</button>

奖励:猴子补丁:Element.clearChildren

  • 我们可以在 JavaScript 中为原型添加一个新的 method-property,以简化将其调用为(其中是任何 HTML 元素对象)。Elementel.clearChildren()el
  • (严格来说,这是一个猴子补丁,而不是一个 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>

评论

6赞 jottos 11/21/2011
在jQuery中,可以考虑以下两个问题: 此方法不仅删除子元素(和其他后代元素),还删除匹配元素集中的任何文本。这是因为,根据 DOM 规范,元素中的任何文本字符串都被视为该元素的子节点。和“为了避免内存泄漏,jQuery在删除元素本身之前,会从子元素中删除其他构造,例如数据和事件处理程序。
35赞 stwissel 3/27/2013
innerHTML 仅在您只处理 HTML 时才有效。如果里面有例如.SVG,只有元素删除才能起作用
73赞 Kenji 9/21/2013
NEVER NEVER NEVER 使用 innerHTML = ''。不要。问题在于,这些项目看起来像是被删除了,但在内部,节点仍然存在并减慢了速度。出于某种原因,您必须删除所有单独的节点。在 Google Chrome 和 IE 中均进行了测试。请考虑删除 innerHTML“解决方案”,因为它是错误的。
6赞 Joeytje50 2/11/2014
@micha jsperf.com/innerhtml-vs-removechild/151 使用 .remove() 甚至更快。
44赞 Chris Middleton 5/13/2015
@vsync 我不认为Kenji的评论是有根据的。做起来比较慢,但我不认为这是“错的”。任何关于内存泄漏的说法都应有证据支持。innerHTML = ''
47赞 user113716 10/18/2010 #2
var myNode = document.getElementById("foo");
var fc = myNode.firstChild;

while( fc ) {
    myNode.removeChild( fc );
    fc = myNode.firstChild;
}

如果有可能有受 jQuery 影响的后代,则必须使用某种方法来清理 jQuery 数据。

$('#foo').empty();

jQuery .empty() 方法将确保 jQuery 与要删除的元素关联的任何数据都将被清理。

如果仅使用删除子项的方法,则该数据将保留。DOM

评论

0赞 Chris Moschini 11/16/2011
innerHTML 方法是迄今为止性能最高的方法。也就是说,jquery 的 .empty() 正在清理的数据:使用递归循环(缓慢,但可能会显着减少内存使用量)消除与子标签关联的 jquery 中的 data(),如果您附加了没有 jquery 的事件,例如使用 .onclick=...,则防止内存泄漏。如果要删除的子项中没有此类事件,则设置 innerHTML 不会泄漏。所以最好的答案是 - 视情况而定。
2赞 Victor Zamanian 5/24/2016
为什么不直接将 firstChild 表达式放在 while 循环的条件下呢?while ( myNode.firstChild ) {
0赞 Valen 12/26/2018
while(fc = myNode.firstChild){ myNode.removeChild(fc); }
48赞 PleaseStand 10/18/2010 #3

如果使用 jQuery:

$('#foo').empty();

如果不这样做:

var foo = document.getElementById('foo');
while (foo.firstChild) foo.removeChild(foo.firstChild);
10赞 DanMan 10/18/2010 #4

如果你只想让节点没有它的子节点,你也可以像这样复制它:

var dupNode = document.getElementById("foo").cloneNode(false);

取决于您要实现的目标。

评论

3赞 Maarten 6/19/2012
也许你甚至可以跟着这个?这可能比逐个删除子项更快,并且应该适用于支持 DOM 的所有内容(因此每种类型的 XML 文档,包括 SVG)。设置 innerHTML 也可能比逐个删除子项更快,但这不适用于 HTML 文档以外的任何内容。应该测试一段时间。parent.replaceChild(cloned, original)
14赞 Matthew 9/9/2012
这不会复制使用 添加的事件侦听器。addEventListener
0赞 DanMan 2/1/2014
如果你能忍受这个限制,那肯定是很快的:jsperf.com/innerhtml-vs-removechild/137
5赞 jeroen 3/16/2013 #5

作为对 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 );

我发现这种方法在替换元素中的字符串时非常有用,如果您不确定节点将包含什么,请不要担心如何清理混乱,而是从头开始。

评论

3赞 Arun Aravind 12/8/2013
有史以来最糟糕的事情。如果要用原始节点的克隆替换原始节点,则会丢失对原始节点的引用。任何事件处理程序和其他绑定都不会起作用。
25赞 Gabe Halsmer 4/3/2013 #6

最快...

var removeChilds = function (node) {
    var last;
    while (last = node.lastChild) node.removeChild(last);
};

感谢安德烈·卢什尼科夫(Andrey Lushnikov)链接到 jsperf.com(很酷的网站!

编辑:需要明确的是,firstChild和lastChild在Chrome中没有性能差异。最好的答案显示了一个很好的性能解决方案。

评论

0赞 cskwg 1/3/2019
同样的事情没有 LINT 警告: clear: function ( container ) { for ( ; ; ;{ var child = container.lastChild; if ( !child ) break; container.removeChild( child ); }}
3赞 Alexey 1/27/2014 #7

innerText是赢家!http://jsperf.com/innerhtml-vs-removechild/133。在之前的所有测试中,父节点的内部 dom 在第一次迭代时被删除,然后在应用于空 div 的 innerHTML 或 removeChild 中删除。

评论

5赞 DanMan 2/1/2014
innerText不过,这是一个专有的 MS 东西。只是说。
1赞 nrabinowitz 12/10/2015
可以肯定的是,这是一个有缺陷的测试 - 它依赖于不是作为 var 而是通过基于 id 的 DOM 查找提供的,并且由于循环多次进行这种缓慢的调用,因此它会受到惩罚。boxwhile
4赞 Henrik 2/1/2014 #8
var empty_element = function (element) {

    var node = element;

    while (element.hasChildNodes()) {              // selected elem has children

        if (node.hasChildNodes()) {                // current node has children
            node = node.lastChild;                 // set current node to child
        }
        else {                                     // last child found
            console.log(node.nodeName);
            node = node.parentNode;                // set node to parent
            node.removeChild(node.lastChild);      // remove last node
        }
    }
}

这将删除元素中的所有节点。

评论

0赞 Periata Breatta 10/23/2016
...我怀疑,因为它不必要的复杂,并且没有解释它是如何工作的(这实际上是不明显的)。
2赞 Noitidart 2/3/2014 #9

我看到人们在做:

while (el.firstNode) {
    el.removeChild(el.firstNode);
}

然后有人说使用更快el.lastNode

但是我认为这是最快的:

var children = el.childNodes;
for (var i=children.length - 1; i>-1; i--) {
    el.removeNode(children[i]);
}

你觉得怎么样?

PS: 这个话题对我来说是救命稻草。我的 firefox 插件被拒绝了,因为我使用了 innerHTML。这是很长一段时间的习惯。然后我找到了这个。我实际上注意到了速度差异。加载时,innerhtml 需要一段时间才能更新,但是通过 addElement 它的即时!

评论

1赞 Nikos M. 10/6/2014
好吧,我认为无论是否最快,一些 JSPerf 测试都可以证明任何一种情况
0赞 Noitidart 10/6/2014
超级工作,感谢您的这些测试。不过,它们不包括那个。但这是我在运行这些测试时得到的: i.imgur.com/Mn61AmI.png 所以在这三个测试中,firstNode 比 lastNode 和 innerHTML 更快,这真的很酷for (var i=0...
0赞 Noitidart 10/6/2014
我添加了测试: jsperf.com/innerhtml-vs-removechild/220 有趣的东西 做el.firstNode方法是最快的方式
8赞 Nathan K 3/12/2014 #10

这是另一种方法:

function removeAllChildren(theParent){

    // Create the Range object
    var rangeObj = new Range();

    // Select all of theParent's children
    rangeObj.selectNodeContents(theParent);

    // Delete everything that is selected
    rangeObj.deleteContents();
}

评论

1赞 DigitalZebra 1/6/2015
这很有趣,但与其他方法相比,它似乎相当慢: jsperf.com/innerhtml-vs-removechild/256
8赞 bjb568 3/29/2014 #11
element.textContent = '';

它就像 innerText,除了标准。它比 慢一点,但它更易于使用,如果您没有太多要删除的内容,则不会对性能产生太大影响。removeChild()

评论

0赞 check_ca 4/23/2014
文本节点不是元素
0赞 check_ca 4/26/2014
对不起,你是对的,它确实删除了所有儿童元素
0赞 pwdst 3/29/2017
这在较旧版本的 Internet Explorer 中不起作用。
140赞 npjohns 4/9/2014 #12

正如 m93a 正确提到的那样,目前公认的答案是错误的(至少在 IE 和 Chrome 中)。innerHTML

Chrome 和 FF 使用这种方法的速度要快得多(这将破坏附加的 jquery 数据):

var cNode = node.cloneNode(false);
node.parentNode.replaceChild(cNode, node);

FF 和 Chrome 遥遥领先,IE 最快:

node.innerHTML = '';

InnerHTML 不会破坏您的事件处理程序或破坏 jquery 引用,它也被推荐为此处的解决方案:https://developer.mozilla.org/en-US/docs/Web/API/Element.innerHTML

最快的 DOM 操作方法(仍然比前两种慢)是范围删除,但在 IE9 之前不支持范围。

var range = document.createRange();
range.selectNodeContents(node);
range.deleteContents();

提到的其他方法似乎具有可比性,但比innerHTML慢得多,除了异常值jquery(1.1.1和3.1.1),它比其他任何方法都慢得多:

$(node).empty();

证据在这里:

http://jsperf.com/innerhtml-vs-removechild/167 http://jsperf.com/innerhtml-vs-removechild/300 https://jsperf.com/remove-all-child-elements-of-a-dom-node-in-javascript(jsperf 重启的新 url,因为编辑旧 url 不起作用)

Jsperf 的“per-test-loop”通常被理解为“per-iteration”,只有第一次迭代有节点要删除,所以结果毫无意义,在发布时,这个线程中的测试设置不正确。

评论

4赞 bryc 3/15/2015
你的 jsperf 完全坏了。这不是很好的证据。
4赞 Ben 5/15/2015
这是目前最好的答案。此线程中的其他所有内容都是虚假信息(!感谢您清理所有那些糟糕的旧测试。
6赞 6/4/2016
“InnerHTML 不会破坏你的事件处理程序或弄乱任何jquery引用”它将孤立保存在 中的数据,导致内存泄漏,因为唯一可用于管理该数据的参考是您刚刚销毁的元素。jQuery.cache
10赞 senderle 3/29/2017
jsperf 测试在这里被破坏了。测试引擎报告以下内容:“错误:在迭代期间未重新创建 Dom 节点,测试结果将毫无意义。
3赞 Scott Means 8/17/2020
我正在学习 DOM 课程,由于看起来 jsperf.com 是 mia 并且可能会持续一段时间,所以我在 jsben.ch 上创建了一个页面。截至今天,仍然是赢家。我已经在这个兔子洞上花了太长时间了,但在 2020 年,我不得不想知道为什么我们还没有 or DOM 方法......innerHTML.clear().empty()
3赞 Chaitanya Bapat 7/19/2016 #13

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

var myNode = document.getElementById("foo");
while(myNode.hasChildNodes())
{
   myNode.removeChild(myNode.lastChild);
}
164赞 Gibolt 11/15/2016 #14

使用现代 Javascript,带有 !remove

const parent = document.getElementById("foo")
while (parent.firstChild) {
    parent.firstChild.remove()
}

这是在 ES5 中写入节点删除的一种较新的方法。它是香草JS,读起来比依赖父母要好得多。

支持所有现代浏览器。

浏览器支持 - 97% 6月 '21

评论

22赞 qix 11/16/2016
for 循环将不起作用,因为 parent.children / parent.childNodes 是实时列表;调用 remove 会修改列表,因此不能保证迭代器遍历所有内容。例如,在 chrome 中,您最终会跳过所有其他节点。最好使用循环。developer.mozilla.org/en-US/docs/Web/API/ParentNode/children developer.mozilla.org/en-US/docs/Web/API/Node/childNodeswhile (parent.firstChild) { parent.removeChild(parent.firstChild); }
4赞 Gibolt 5/8/2017
很酷的速记,虽然可读性较差:while (parent.firstChild && !parent.firstChild.remove());
3赞 8/13/2018
当性能不是什么大问题时,一句话:[...parent.childNodes].forEach(el => el.remove());
3赞 John Henckel 8/21/2018
这在 Typescript 中不起作用......请改用while (selectElem.firstElementChild) { selectElem.firstElementChild.remove(); }
4赞 magiccrafter 1/27/2017 #15

有几种方法可以实现这一点:

最快():

while (node.lastChild) {
  node.removeChild(node.lastChild);
}

替代方案(较慢):

while (node.firstChild) {
  node.removeChild(node.firstChild);
}

while (node.hasChildNodes()) {
  node.removeChild(node.lastChild);
}

使用建议的选项进行基准测试

1赞 r00t hkr 7/14/2017 #16

通常,JavaScript 使用数组来引用 DOM 节点的列表。因此,如果您有兴趣通过 HTMLElements 数组来执行此操作,这将很好地工作。另外,值得注意的是,因为我使用的是数组引用而不是 JavaScript 原型,所以这应该适用于任何浏览器,包括 IE。

while(nodeArray.length !== 0) {
  nodeArray[0].parentNode.removeChild(nodeArray[0]);
}
2赞 Neelansh Verma 5/21/2018 #17

为什么我们不遵循这里最简单的方法“删除”在里面循环。

const foo = document.querySelector(".foo");
while (foo.firstChild) {
  foo.firstChild.remove();     
}
  • 选择父 div
  • 在 While 循环中使用 “remove” 方法消除第一个子元素,直到没有剩下任何子元素。

评论

0赞 Ignacio Ara 5/21/2018
请解释您的代码行,以便其他用户了解其功能。谢谢!
0赞 Neelansh Verma 5/21/2018
@IgnacioAra完成了!
6赞 Ado Ren 9/10/2018 #18

这是我通常做的:

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

瞧,稍后您可以使用以下命令清空任何 dom 元素:

anyDom.empty()

评论

0赞 Full Stack Alien 10/27/2019
我喜欢这个解决方案!我应该使用它而不是将innerHTML设置为空白字符串的任何原因吗?
0赞 Ado Ren 10/27/2019
性能:较差,被认为是不良做法domEl.innerHTML = ""
1赞 Harry Chilinguerian 11/15/2018 #19

刚刚看到有人在另一个中提到这个问题,并认为我会添加一个我还没有看到的方法:

function clear(el) {
    el.parentNode.replaceChild(el.cloneNode(false), el);
}

var myNode = document.getElementById("foo");
clear(myNode);

clear 函数是获取元素并使用父节点将自身替换为没有子节点的副本。如果元素稀疏,则性能提升不大,但当元素有一堆节点时,性能提升就会实现。

评论

1赞 Félix Adriyel Gagnon-Grenier 11/16/2018
实际上,这里似乎提到了它 stackoverflow.com/a/15441725/576767
0赞 Harry Chilinguerian 11/20/2018
菲利克斯我一定错过了,谢谢你的更正+1。
5赞 emu 12/7/2018 #20

使用范围循环对我来说是最自然的:

for (var child of node.childNodes) {
    child.remove();
}

根据我在 Chrome 和 Firefox 中的测量,它的速度大约慢了 1.3 倍。在正常情况下,这可能无关紧要。

3赞 Thomas 11/26/2019 #21
 let el = document.querySelector('#el');
 if (el.hasChildNodes()) {
      el.childNodes.forEach(child => el.removeChild(child));
 }
1赞 Dolph Roger 12/10/2019 #22

仅功能方法:

const domChildren = (el) => Array.from(el.childNodes)
const domRemove = (el) => el.parentNode.removeChild(el)
const domEmpty = (el) => domChildren(el).map(domRemove)

domChildren 中的“childNodes”将给出一个直接子元素的 nodeList,当找不到任何元素时,该元素为空。为了映射 nodeList,domChildren 将其转换为数组。domEmpty 将函数 domRemove 映射到删除它的所有元素上。

用法示例:

domEmpty(document.body)

从 body 元素中删除所有子元素。

1赞 harish kumar 7/12/2020 #23

您可以从容器中删除所有子元素,如下所示:

function emptyDom(selector){
 const elem = document.querySelector(selector);
 if(elem) elem.innerHTML = "";
}

现在,您可以调用该函数并传递选择器,如下所示:

如果元素有 id = foo

emptyDom('#foo');

如果元素有 class = foo

emptyDom('.foo');

if 元素有标签 = <div>

emptyDom('div')
27赞 Marc M. 7/28/2020 #24

用。elm.replaceChildren()

它是实验性的,没有广泛的支持,但是在没有参数的情况下执行时,它会做你要求的事情,而且它比遍历每个孩子并删除它更有效。如前所述,替换为空字符串需要浏览器进行 HTML 解析。innerHTML

MDN 文档

更新它现在得到广泛支持

评论

0赞 Marc M. 10/20/2020
caniuse.com/?search=replaceChildren最新版本的 Chrome 和 Safari 刚刚得到了它。给它几个月的时间。天哪,我喜欢自动更新。
0赞 NateS 10/15/2021
空字符串上发生了多少 HTML 解析?
4赞 12Me21 8/6/2020 #25

element.innerHTML = ""(或 .textContent)是迄今为止最快的解决方案

这里的大多数答案都是基于有缺陷的测试

例如: https://jsperf.com/innerhtml-vs-removechild/15
此测试不会在每次迭代之间向元素添加新的子元素。第一次迭代将删除元素的内容,然后每个其他迭代将不执行任何操作。 在本例中,速度更快,因为 box.lastChild 在 99% 的时间内为 null
while (box.lastChild) box.removeChild(box.lastChild)

这是一个适当的测试:https://jsperf.com/innerhtml-conspiracy

最后,不要使用 .这会将节点替换为没有其子节点的自身副本。但是,这不会保留事件侦听器,并中断对节点的任何其他引用。node.parentNode.replaceChild(node.cloneNode(false), node)

9赞 Marco Balestra 11/12/2020 #26

Ecma6 使它变得简单而紧凑

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

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

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

myNode.textContent = '';

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

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

476赞 Mason Freed 12/23/2020 #27

在 2022+ 中,使用 API!replaceChildren()

现在可以使用(支持跨浏览器)replaceChildren API 替换所有子项:

container.replaceChildren(...arrayOfNewChildren);

这将同时执行以下两项操作:

  • 删除所有现有子项,以及
  • 在一个操作中追加所有给定的新子项。

您还可以使用相同的 API 仅删除现有子项,而不替换它们:

container.replaceChildren();

Chrome/Edge 86+、Firefox 78+ 和 Safari 14+ 完全支持此功能。这是完全指定的行为。这可能比这里提出的任何其他方法都快,因为删除旧子项和添加新子项不需要 ,并且只需一步而不是多个步骤即可完成。innerHTML

评论

3赞 Mason Freed 4/30/2021
MDN 数据现已更正,并显示完全的跨浏览器支持:caniuse.com/?search=replacechildren
7赞 spkrtn 5/15/2021
遗憾的是@Polaris878自 2018 年以来一直没有出现。这应该是新的公认的答案。
2赞 Mason Freed 6/28/2022
@ygoe,情况不应该如此。你能举个例子吗?下面是我的示例代码:jsbin.com/xopapef,它使用包含 10,000 个子项的目标元素。至少在 Chrome 中,它在这两种情况下都只显示一个突变观察者调用。你看到不同的东西了吗?如果是这样,请说明您使用的浏览器和平台。(至少对我而言,我的演示还表明 replaceChildren() 至少和 textContent 一样快,而且通常更快。
2赞 Mason Freed 6/28/2022
我在 Mac、Chrome、Firefox 和 Safari 上运行了上面链接的网站,这三个人都同意:只有一个突变观察者调用。replaceChildren() 在这三个方面都略快一些。如果您看到不同的东西,请告诉我。
6赞 DigitalZebra 10/16/2022
将其更改为公认的答案,因为它现在是建议的现代方法:)
2赞 Chester Fung 7/29/2021 #28

ES6+ 浏览器(2016 年后发布的主要浏览器)的最佳删除方法:

也许有很多方法可以做到这一点,例如 Element.replaceChildren()。 我想向你展示一个有效的解决方案,只有一个重绘和重排支持所有ES6+浏览器

function removeChildren(cssSelector, parentNode){
    var elements = parentNode.querySelectorAll(cssSelector);
    let fragment = document.createDocumentFragment(); 
    fragment.textContent=' ';
    fragment.firstChild.replaceWith(...elements);
}

用法: :删除所有 className 在removeChildren('.foo',document.body);foo<body>

评论

1赞 Danny '365CSI' Engelman 10/30/2021
不需要只是做而不是textContentfragment.replaceChildren(...elements)fragment.firstChild.replaceWith(...elements)
1赞 Chester Fung 5/8/2022
@Danny'365CSI'Engelman 是一种相对较新的 DOM 方法。(例如 FireFox >=78),而可以与 Firefox>=49 一起运行。如果您的目标浏览器是最新版本而不考虑 Waterfox Classic,可能会更好。replaceChildrenreplaceWithreplaceChildren
6赞 ShivCK 12/22/2022 #29

用于迭代从 DOM 中删除 a 的所有子项的单行代码node

Array.from(node.children).forEach(c => c.remove())

[...node.children].forEach(c => c.remove())
5赞 Maxim 3/31/2023 #30

我查看了所有问题,并决定测试最关键测试用例的性能:

  • 我们需要清除内容
  • 我们需要保留原始元素
  • 我们需要删除很多子元素

所以我的HTML:

<div id="target">
  <div><p>Title</p></div>
  <!-- 1000 at all -->
  <div><p>Title</p></div>
</div>
// innerHTML
target.innerHTML = "";
// lastChild
while (target.hasChildNodes()) {
    target.removeChild(target.lastChild);
}
// firstChild
while (target.hasChildNodes()) {
    target.removeChild(target.firstChild);
}
// replaceChildren
target.replaceChildren();
结果:
Checked test: innerHTML x 1,222,273 ops/sec ±0.47% (63 runs sampled)
Checked test: lastChild x 1,336,734 ops/sec ±0.87% (65 runs sampled)
Checked test: firstChild x 1,313,521 ops/sec ±0.74% (64 runs sampled)
Checked test: replaceChildren x 743,076 ops/sec ±1.08% (53 runs sampled)

Checked test: innerHTML x 1,202,727 ops/sec ±0.83% (63 runs sampled)
Checked test: lastChild x 1,360,350 ops/sec ±0.72% (65 runs sampled)
Checked test: firstChild x 1,348,498 ops/sec ±0.78% (63 runs sampled)
Checked test: replaceChildren x 743,076 ops/sec ±0.86% (53 runs sampled)

Checked test: innerHTML x 1,191,838 ops/sec ±0.73% (62 runs sampled)
Checked test: lastChild x 1,352,657 ops/sec ±1.42% (63 runs sampled)
Checked test: firstChild x 1,327,664 ops/sec ±1.27% (65 runs sampled)
Checked test: replaceChildren x 754,166 ops/sec ±1.88% (61 runs sampled)
结论

现代 API 最慢。第一个孩子和最后一个孩子的方式是相等的,如果与多个案例进行比较,可能会出现一些副作用。但您可以在这里并排看到:

Checked test: firstChild x 1,423,497 ops/sec ±0.53% (63 runs sampled)
Checked test: lastChild x 1,422,560 ops/sec ±0.36% (66 runs sampled)

Checked test: firstChild x 1,368,175 ops/sec ±0.57% (65 runs sampled)
Checked test: lastChild x 1,381,759 ops/sec ±0.39% (66 runs sampled)

Checked test: firstChild x 1,372,109 ops/sec ±0.37% (66 runs sampled)
Checked test: lastChild x 1,355,811 ops/sec ±0.35% (65 runs sampled)
Checked test: lastChild x 1,364,830 ops/sec ±0.65% (64 runs sampled)
Checked test: firstChild x 1,365,617 ops/sec ±0.41% (65 runs sampled)

Checked test: lastChild x 1,389,458 ops/sec ±0.50% (63 runs sampled)
Checked test: firstChild x 1,387,861 ops/sec ±0.40% (64 runs sampled)

Checked test: lastChild x 1,388,208 ops/sec ±0.43% (65 runs sampled)
Checked test: firstChild x 1,413,741 ops/sec ±0.47% (65 runs sampled)

PS 浏览器:Firefox 111.0.1