如何在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,我不使用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 ="";

})

其他回答

元素。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)。这将用节点本身的副本替换它的子节点。但是,这不会保留事件侦听器,并破坏对该节点的任何其他引用。

我看到人们这样做:

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它的瞬间!

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

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

最快的…

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

感谢Andrey Lushnikov提供的jsperf.com链接(很酷的网站!)

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

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

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