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

时间:2010-10-17 20:51:00

标签: javascript dom

如何在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的答案,那么可以提供额外的分数。

36 个答案:

答案 0 :(得分:1396)

选项1(慢得多,见下面的评论):

var myNode = document.getElementById("foo");
myNode.innerHTML = '';

选项2(快得多):

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

答案 1 :(得分:90)

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

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操作方法(仍比前两个慢)是Range删除,但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”,并且只有第一次迭代才有删除的节点,因此结果毫无意义,在发布时,此线程中的测试设置不正确。

答案 2 :(得分:43)

2020 年更新 - 使用 replaceChildren() API!

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

container.replaceChildren(...arrayOfNewChildren);

这将同时执行以下两项操作:a) 删除所有现有子项,以及 b) 在一次操作中附加所有给定的新子项。

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

container.replaceChildren();

Chrome/Edge 86+、Firefox 78+ 和 Safari 14+ 完全支持此功能。(请注意,目前 Safari 的 MDN 数据不正确。)fully specified行为。这可能比这里任何其他建议的方法更快,因为移除旧子节点和添加新子节点 a) 不需要 innerHTML,并且 b) 一步完成多个。

答案 3 :(得分:41)

var myNode = document.getElementById("foo");
var fc = myNode.firstChild;

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

如果你有任何机会让jQuery受影响的后代,那么你必须使用一些清理jQuery数据的方法。

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

The jQuery .empty() method将确保清除与要删除的元素相关联的jQuery的任何数据。

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

答案 4 :(得分:34)

如果你使用jQuery:

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

如果你不这样做:

var foo = document.getElementById('foo');
while (foo.firstChild) foo.removeChild(foo.firstChild);

答案 5 :(得分:33)

使用现代Javascript,remove

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

这是在ES5中编写节点删除的更新方法。它是vanilla JS并且比以前的版本更好地读取

大多数用户应该使用现代浏览器,或者您可以根据需要进行细分。

Browser Support - 2014年5月94%

答案 6 :(得分:19)

最快......

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

感谢Andrey Lushnikov his link to jsperf.com(很酷的网站!)。

编辑:很明显,Chrome在firstChild和lastChild之间没有任何性能差异。最佳答案显示了良好的性能解决方案。

答案 7 :(得分:9)

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

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

取决于你想要达到的目标。

答案 8 :(得分:6)

element.textContent = '';

它与innerText相似,但标准除外。它a bit slowerremoveChild()更快,但它更容易使用,如果你没有太多的东西,它将不会产生很大的性能差异删除。

答案 9 :(得分:5)

这是另一种方法:

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();
}

答案 10 :(得分:4)

回应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 );

我发现这个方法在替换元素中的字符串时非常有用,如果你不确定节点将包含什么,而不是担心如何清理混乱,那么就开始新鲜了。

答案 11 :(得分:4)

elm.replaceChildren()

这是实验性的,没有广泛的支持,但是在不使用参数的情况下执行将满足您的要求,并且比遍历每个孩子并将其删除要更有效。如前所述,用一个空字符串替换innerHTML将需要在浏览器部分进行HTML解析。

文档here

答案 12 :(得分:3)

我看到有人在做:

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进行更新!

答案 13 :(得分:3)

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
        }
    }
}

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

答案 14 :(得分:3)

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

最快():

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

替代品(较慢):

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

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

Benchmark with the suggested options

答案 15 :(得分:2)

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

答案 16 :(得分:2)

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

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

答案 17 :(得分:2)

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

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

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

答案 18 :(得分:2)

这是我通常要做的:

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

瞧,以后您可以使用:

清空任何dom元素。
anyDom.empty()

答案 19 :(得分:1)

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

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

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

用法:removeChildren('.foo',document.body);:删除foo中所有className为<body>的元素

答案 20 :(得分:1)

Ecma6使其变得轻松而紧凑

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

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

如果存在属于myNode的文本节点,则无法使用CSS选择器选择它们,在这种情况下,我们还必须应用:

myNode.textContent = '';

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

.textContent.innerText.innerHTML更有效率,请参阅:MDN

答案 21 :(得分:1)

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

答案 22 :(得分:1)

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

while(nodeArray.length !== 0) {
  nodeArray[0].parentNode.removeChild(nodeArray[0]);
}

答案 23 :(得分:0)

为什么我们不遵循这里最简单的方法&#34;删除&#34;在里面打圈。

const foo = document.querySelector(".foo");
while (foo.firstChild) {
  foo.firstChild.remove();     
}
  • 选择父div
  • 使用&#34;删除&#34; While循环中用于消除第一个子元素的方法,直到没有剩余。

答案 24 :(得分:0)

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

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

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

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

答案 25 :(得分:0)

仅适用于功能的方法:

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元素中删除所有子元素。

答案 26 :(得分:0)

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

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

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

如果元素的ID为 foo

emptyDom('#foo');

如果元素具有class = foo

emptyDom('.foo');

如果元素具有标签= << strong> div >

emptyDom('div')

答案 27 :(得分:0)

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

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

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

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

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

答案 28 :(得分:0)

如果您想清空整个父级 DOM 那么这很简单...

只需使用 .empty()

function removeAll() {
  $('#parent').empty();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button onclick="removeAll()">Remove all the element of parent</button>
<div id="parent">
  <h3>Title</h3>
  <p>Child 1</p>
  <p>Child 2</p>
  <p>Child 3</p>
</div>

答案 29 :(得分:-1)

简单快速地使用for循环!

https://bar.com.s/media/hgfr2um5oqibs8lbjbv7.jpg

这在var myNode = document.getElementById("foo"); for(var i = myNode.childNodes.length - 1; i >= 0; --i) { myNode.removeChild(myNode.childNodes[i]); } 标签中不起作用!

答案 30 :(得分:-1)

最简单的方法:

let container = document.getElementById("containerId");
container.innerHTML = "";

答案 31 :(得分:-1)

只是IE:

parentElement.removeNode(true);

true - 意味着深度移除 - 这意味着所有孩子也被移除

答案 32 :(得分:-1)

jQuery中的其他方法

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

答案 33 :(得分:-3)

如果您想将某些内容放回divinnerHTML可能会更好。

我的例子:

<ul><div id="result"></div></ul>

<script>
  function displayHTML(result){
    var movieLink = document.createElement("li");
    var t = document.createTextNode(result.Title);
    movieLink.appendChild(t);
    outputDiv.appendChild(movieLink);
  }
</script>

如果我使用.firstChild.lastChild方法,之后displayHTML()函数无效,但.innerHTML方法没有问题。

答案 34 :(得分:-4)

这是一个纯粹的javascript我没有使用jQuery但是在所有浏览器中工作甚至IE浏览器都很容易理解

   <div id="my_div">
    <p>Paragraph one</p>
    <p>Paragraph two</p>
    <p>Paragraph three</p>
   </div>
   <button id ="my_button>Remove nodes ?</button>

   document.getElementById("my_button").addEventListener("click",function(){

  let parent_node =document.getElemetById("my_div"); //Div which contains paagraphs

  //Let find numbers of child inside the div then remove all
  for(var i =0; i < parent_node.childNodes.length; i++) {
     //To avoid a problem which may happen if there is no childNodes[i] 
     try{
       if(parent_node.childNodes[i]){
         parent_node.removeChild(parent_node.childNodes[i]);
       }
     }catch(e){
     }
  }

})

or you may simpli do this which is a quick way to do

document.getElementById("my_button").addEventListener("click",function(){

 let parent_node =document.getElemetById("my_div");
 parent_node.innerHTML ="";

})

答案 35 :(得分:-7)

使用jQuery:

$("#foo").find("*").remove();