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

2020/09/19 17:31 · javascript ·  · 0评论

我将如何删除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答案,则需要加分。

选项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

  • 如上,但使用.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>

选项2 A:循环删除以下所有内容lastChild

  • 早先对此答案进行了修改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>

选项2 B:循环删除所有内容lastElementChild

  • 这种方法保留了父级的所有非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>

奖励:Element.clearChildren猴子补丁:

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

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

Chrome和FF使用此方法的速度显着提高(这将破坏附加的jquery数据):

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

对于FF和Chrome来说,是遥不可及的,在IE中最快:

node.innerHTML = '';

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

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

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

提到的其他方法似乎是可比较的,但是比例外的jquery(1.1.1和3.1.1)慢得多,它比innerHTML慢得多,后者比其他任何东西都慢得多:

$(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”,并且只有第一个迭代有要删除的节点,因此结果是没有意义的,在发布时,此线程中的测试设置不正确。

使用现代Javascript,搭配remove

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

这是在ES5中写入删除节点的新方法。这是香草JS,读得多漂亮不是依靠父母。

支持所有现代浏览器。

浏览器支持 -2020年6月96%

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删除子项的方法,该数据将保留。

如果您使用jQuery:

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

如果您不这样做:

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

最快的...

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

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

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

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

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

取决于您要实现的目标。

这是另一种方法:

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();
}
element.textContent = '';

就像innerText一样,标准除外。一些removeChild(),但使用起来更容易,并且如果您没有太多要删除的内容,则不会对性能造成太大影响。

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

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

这是我通常的工作:

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

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

anyDom.empty()

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

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

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

有两种选择可以实现:

最快的 ():

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

替代方案(较慢):

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

while (node.hasChildNodes()) {
  node.removeChild(node.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
        }
    }
}

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

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

通过Java脚本删除节点的子节点的最简单方法

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

我看到人们在做:

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立即进行!

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

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

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

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

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

刚看到有人在另一个地方提到这个问题,并以为我会添加一个我尚未看到的方法:

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

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

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

仅功能方法:

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

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

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

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

如果元素具有id = foo

emptyDom('#foo');

如果元素具有class = foo

emptyDom('.foo');

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

emptyDom('div')

elm.replaceChildren()

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

文档在这里

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

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

例如:https :
//jsperf.com/innerhtml-vs-removechild/15


此测试不会在每次迭代之间将新的子代添加到元素中。
第一次迭代将删除元素的内容,然后其他所有迭代将不执行任何操作。在这种情况下,
while (box.lastChild) box.removeChild(box.lastChild)速度更快,因为box.lastChild是null99%的时间

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

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

仅仅是IE:

parentElement.removeNode(true);

true -意味着进行深层移除-这意味着所有孩子也都被移除了

最简单的方法:

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

简单快速地使用for循环!

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

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

这在<span>标签中不起作用

jQuery中的其他方式

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

如果您想放些东西div,那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>

如果我使用.firstChildor .lastChild方法,该displayHTML()函数此后将无法正常工作,但是该.innerHTML方法没有问题

本文地址:http://javascript.askforanswer.com/zaijavascriptzhongshanchudomjiediandesuoyouziyuansu.html
文章标签: ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!