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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3955229/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 06:50:36  来源:igfitidea点击:

Remove all child elements of a DOM node in JavaScript

javascriptdom

提问by Polaris878

How would I go about removing all of the child elements of a DOM node in JavaScript?

我将如何在 JavaScript 中删除 DOM 节点的所有子元素?

Say I have the following (ugly) HTML:

假设我有以下(丑陋的)HTML:

<p id="foo">
    <span>hello</span>
    <div>world</div>
</p>

And I grab the node I want like so:

我像这样抓住我想要的节点:

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

How could I remove the children of fooso that just <p id="foo"></p>is left?

我怎么能移除 的孩子,foo这样就<p id="foo"></p>剩下了?

Could I just do:

我能不能这样做:

myNode.childNodes = new Array();

or should I be using some combination of removeElement?

或者我应该使用removeElement?

I'd like the answer to be straight up DOM; though extra points if you also provide an answer in jQuery along with the DOM-only answer.

我希望答案是直接的 DOM;如果您还提供 jQuery 中的答案以及仅 DOM 的答案,则可以加分。

回答by Gabriel McAdams

Option 1 A: Clearing innerHTML.

选项 1 A:清算innerHTML

  • This approach is simple, but might not be suitable for high-performance applications because it invokes the browser's HTML parser (though browsers mayoptimize for the case where the value is an empty string).
  • 这种方法很简单,但可能不适合高性能应用程序,因为它会调用浏览器的 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>

Option 1 B: Clearing textContent

选项 1 B:清算 textContent

  • As above, but use .textContent. According to MDNthis will be faster than innerHTMLas browsers won't invoke their HTML parsers and will instead immediately replace all children of the element with a single #textnode.
  • 如上所述,但使用.textContent. 根据 MDN,这将比innerHTML浏览器不会调用它们的 HTML 解析器而是立即用单个#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>

Option 2 A: Looping to remove every lastChild:

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

  • An earlier edit to this answer used firstChild, but this is updated to use lastChildas in computer-science, in general, it's significantly faster to remove the lastelement of a collection than it is to remove the first element (depending on how the collection is implemented).
  • The loop continues to check for firstChildjust in caseit's faster to check for firstChildthan lastChild(e.g. if the element list is implemented as a directed linked-list by the UA).
  • 使用了对该答案的较早编辑firstChild,但已更新lastChild为在计算机科学中使用,一般来说,删除集合的最后一个元素比删除第一个元素要快得多(取决于集合的实现方式) )。
  • 循环继续检查,firstChild以防检查速度firstChildlastChild(例如,如果元素列表由 UA 实现为有向链表)。

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>

Option 2 B: Looping to remove every lastElementChild:

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

  • This approach preserves all non-Element(namely #textnodes and <!-- comments -->) children of the parent (but not their descendants) - and this may be desirable in your application (e.g. some templating systems that use inline HTML comments to store template instructions).
  • This approach wasn't used until recent years as Internet Explorer only added support for lastElementChildin IE9.
  • 这种方法保留所有非Element(即#text节点和<!-- comments -->)父级(但不是它们的后代)的子级 - 这在您的应用程序中可能是可取的(例如,一些使用内联 HTML 注释来存储模板指令的模板系统)。
  • 这种方法直到最近几年才被使用,因为 Internet Explorer 只lastElementChild在 IE9 中添加了支持。

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>

Bonus: Element.clearChildrenmonkey-patch:

奖励:Element.clearChildren猴子补丁:

  • We can add a new method-property to the Elementprototype in JavaScript to simplify invoking it to just el.clearChildren()(where elis anyHTML element object).
  • (Strictly speaking this is a monkey-patch, not a polyfill, as this is not a standard DOM feature or missing feature. Note that monkey-patching is rightfully discouraged in many situations.)
  • 我们可以向ElementJavaScript 中的原型添加一个新的方法属性,以简化对它的调用el.clearChildren()(其中el任何HTML 元素对象)。
  • (严格来说,这是一个monkey-patch,而不是polyfill,因为这不是标准的DOM 特性或缺失的特性。请注意,在许多情况下不鼓励使用monkey-patching。)

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>

回答by npjohns

The currently accepted answer is wrong about innerHTMLbeing slower (at least in IE and Chrome), as m93a correctly mentioned.

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

Chrome and FF are dramatically faster using this method (which will destroy attached jquery data):

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

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

in a distant second for FF and Chrome, and fastest in IE:

对于 FF 和 Chrome,在一秒钟内,在 IE 中最快:

node.innerHTML = '';

InnerHTML won't destroy your event handlers or break jquery references, it's also recommended as a solution here: https://developer.mozilla.org/en-US/docs/Web/API/Element.innerHTML.

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

The fastest DOM manipulation method (still slower than the previous two) is the Range removal, but ranges aren't supported until IE9.

最快的 DOM 操作方法(仍然比前两种慢)是 Range 移除,但直到 IE9 才支持 Ranges。

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

The other methods mentioned seem to be comparable, but a lot slower than innerHTML, except for the outlier, jquery (1.1.1 and 3.1.1), which is considerably slower than anything else:

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

$(node).empty();

Evidence here:

证据在这里:

http://jsperf.com/innerhtml-vs-removechild/167http://jsperf.com/innerhtml-vs-removechild/300https://jsperf.com/remove-all-child-elements-of-a-dom-node-in-javascript(New url for jsperf reboot because editing the old url isn't working)

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

Jsperf's "per-test-loop" often gets understood as "per-iteration", and only the first iteration has nodes to remove so the results are meaningless, at time of posting there were tests in this thread set up incorrectly.

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

回答by Gibolt

Use modern Javascript, with remove!

使用现代 Javascript,带有remove!

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

This is a newer way to write node removal in ES5. It is vanilla JS and reads muchnicer than previous versions.

这是一种在 ES5 中编写节点删除的较新方法。它是 vanilla JS,比以前的版本读起来好得多。

Most users should have modern browsers or you can transpile down if needed.

大多数用户应该拥有现代浏览器,或者您可以根据需要进行转换。

Browser Support- 95% Dec 2019

浏览器支持- 95% 2019 年 12 月

回答by user113716

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

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


If there's any chance that you have jQuery affected descendants, then you mustuse some method that will clean up jQuery data.

如果您有任何机会影响 jQuery 的后代,那么您必须使用某种方法来清理 jQuery 数据。

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

The jQuery .empty()methodwill ensure that any data that jQuery associated with elements being removed will be cleaned up.

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

If you simply use DOMmethods of removing the children, that data will remain.

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

回答by PleaseStand

If you use jQuery:

如果您使用 jQuery:

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

If you don't:

如果你没有:

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

回答by Gabe Halsmer

The fastest...

最快的...

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

Thanks to Andrey Lushnikov for his link to jsperf.com(cool site!).

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

EDIT: to be clear, there is no performance difference in Chrome between firstChild and lastChild. The top answer shows a good solution for performance.

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

回答by DanMan

If you only want to have the node without its children you could also make a copy of it like this:

如果您只想拥有没有子节点的节点,您也可以像这样制作它的副本:

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

Depends on what you're trying to achieve.

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

回答by Nathan K

Here's another approach:

这是另一种方法:

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

回答by bjb568

element.textContent = '';

It's like innerText, except standard. It's a bit slowerthan removeChild(), but it's easier to use and won't make much of a performance difference if you don't have too much stuff to delete.

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

回答by jeroen

In response to DanMan, Maarten and Matt. Cloning a node, to set the text is indeed a viable way in my results.

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

Also this works for nodes not in the dom which return null when trying to access the parentNode. In addition, if you need to be safe a node is empty before adding content this is really helpful. Consider the use case underneath.

这也适用于不在 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 );

I find this method very useful when replacing a string inside an element, if you are not sure what the node will contain, instead of worrying how to clean up the mess, start out fresh.

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