代码之家  ›  专栏  ›  技术社区  ›  DigitalZebra

在javascript中删除dom节点的所有子元素

  •  692
  • DigitalZebra  · 技术社区  · 15 年前

    如何删除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-only答案,则需要额外的分数。

    27 回复  |  直到 7 年前
        1
  •  1370
  •   Denilson Sá Maia    12 年前

    选项1(速度慢得多,请参阅下面的注释):

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

    选项2(更快):

    var myNode = document.getElementById("foo");
    while (myNode.firstChild) {
        myNode.removeChild(myNode.firstChild);
    }
    
        2
  •  88
  •   Maciej Gurban    9 年前

    当前接受的答案是错误的,因为innerhtml速度较慢(至少在IE和Chrome中),正如M93A正确提到的。

    使用这种方法,chrome和ff速度显著加快(这将破坏附加的jquery数据):

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

    在远处的一秒钟内出现FF和Chrome,在IE中最快:

    node.innerHTML = '';
    

    内层HTML 不会破坏事件处理程序或中断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 (因为编辑旧的URL不起作用,所以jsper重新启动的新URL)

    JSperf的“每个测试循环”通常被理解为“每个迭代”,只有第一个迭代有要删除的节点,所以结果是无意义的,在发布时,这个线程中的测试设置不正确。

        3
  •  41
  •   user113716    15 年前
    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
  •  33
  •   PleaseStand    13 年前

    如果使用jquery:

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

    如果你不这样做:

    var foo = document.getElementById('foo');
    while (foo.firstChild) foo.removeChild(foo.firstChild);
    
        5
  •  30
  •   Gibolt    7 年前

    使用现代的javascript, remove !

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

    这是一种在ES5中写入节点删除的新方法。它是香草JS和阅读 许多的 比以前的版本更好。

    大多数用户应该有现代的浏览器,或者你可以在需要的时候发泄出来。

    Browser Support - 93% APR 2019

        6
  •  19
  •   Gabe Halsmer    7 年前

    最快的…

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

    感谢安德烈·卢什尼科夫 his link to jsperf.com (酷网站!).

    编辑:要清楚,firstchild和lastchild在chrome中没有性能差异。上面的答案显示了一个很好的性能解决方案。

        7
  •  9
  •   DanMan    10 年前

    如果只想让节点不带子节点,也可以这样复制它:

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

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

        8
  •  5
  •   bjb568 Ispirer SQLWays Migrations    12 年前
    element.textContent = '';
    

    除了标准外,它和InnerText很像。它是 a bit slower removeChild() 但是,如果没有太多要删除的内容,它更容易使用,并且不会对性能产生太大影响。

        9
  •  5
  •   Nathan K    11 年前

    另一种方法是:

    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
  •   jeroen    13 年前

    作为对丹曼、马顿和马特的回应。克隆一个节点,设置文本,在我的结果中确实是一种可行的方法。

    // @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时返回空值。此外,如果需要确保安全,则在添加内容之前节点是空的,这非常有用。考虑下面的用例。

    // @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
  •  3
  •   magiccrafter    9 年前

    实现这一点有两种选择:

    最快():

    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

        12
  •  3
  •   Noitidart    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: 这个话题对我来说是个救命稻草。我的火狐插件被拒绝了,因为我使用了innerhtml。长期以来它一直是一种习惯。然后我发现了这个。实际上我注意到了一个速度差。加载时,innerhtml花了一段时间进行更新,但是addelement会立即更新!

        13
  •  3
  •   YakovL Naresh Kumar Nakka    7 年前
    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
  •  2
  •   Alexey    10 年前

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

        15
  •  2
  •   Chaitanya Bapat    10 年前

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

    var myNode = document.getElementById("foo");
    while(myNode.hasChildNodes())
    {
       myNode.removeChild(myNode.lastChild);
    }
    
        16
  •  2
  •   Ado Ren    7 年前

    我通常做的是:

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

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

    anyDom.empty()
    
        17
  •  2
  •   emu    7 年前

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

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

    根据我在Chrome和Firefox上的测量,它慢了大约1.3倍。在正常情况下,这也许无关紧要。

        18
  •  1
  •   r00t hkr    9 年前

    通常,javascript使用数组来引用dom节点列表。因此,如果您有兴趣通过htmlelements数组来实现这一点,那么这将很好地工作。另外,值得注意的是,因为我使用的是数组引用,而不是javascript协议,这应该在任何浏览器中都可以使用,包括IE。

    while(nodeArray.length !== 0) {
      nodeArray[0].parentNode.removeChild(nodeArray[0]);
    }
    
        19
  •  0
  •   Neelansh Verma    8 年前

    为什么我们不按照最简单的方法来“删除”这个循环。

    const foo = document.querySelector(".foo");
    while (foo.firstChild) {
      foo.firstChild.remove();     
    }
    
    • 选择父分区
    • 在while循环中使用“remove”方法来消除第一个子元素,直到没有剩余元素为止。
        20
  •  0
  •   Harry Chilinguerian    7 年前

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

    function clear(el) {
        el.parentNode.replaceChild(el.cloneNode(false), el);
    }
    
    var myNode = document.getElementById("foo");
    clear(myNode);
    

    clear函数接受元素,并使用父节点将其自身替换为不带子节点的副本。如果元素是稀疏的,则性能增益不大,但是当元素具有多个节点时,性能增益就实现了。

        21
  •  -1
  •   Anoop    14 年前

    jquery中的其他方法

    var foo = $("#foo");
    foo.children().remove();
    or
    $("*", foo ).remove();
    or
    foo.html("");
    
        22
  •  -1
  •   Maciej Gurban    9 年前

    仅仅是IE:

    parentElement.removeNode(true);
    

    true -深度移除的方法-也就是说所有的孩子都被移除

        23
  •  -1
  •   milosz    8 年前

    最简单的方法:

    let container = document.getElementById("containerId");
    container.innerHTML = "";
    
        24
  •  -1
  •   MOHIT KARKAR    7 年前

    简单快速的循环使用!!

    var myNode = document.getElementById("foo");
    
        for(var i = myNode.childNodes.length - 1; i >= 0; --i) {
          myNode.removeChild(myNode.childNodes[i]);
        }
    

    这不适用于 <span> 标签!

        25
  •  -3
  •   Axel    8 年前

    如果你想把东西放回去 div , the innerHTML 可能更好。

    我的例子:

    <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 方法。

        26
  •  -4
  •   Ir Calif    7 年前

    这是一个纯粹的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 ="";
    
    })
    
        27
  •  -7
  •   Arnaud F.    15 年前

    使用jQuery:

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