Remove all child elements of a DOM node in JavaScript
如何删除javascript中DOM节点的所有子元素?
假设我有以下(丑陋的)HTML:
1 2 3 4 5 | <p id="foo"> <span>hello</span> world </p> |
我抓取我想要的节点,就像这样:
1 | var myNode = document.getElementById("foo"); |
我怎样才能去掉EDOCX1的子代(0),只剩下EDOCX1的子代(1)?
我可以这样做吗:
1 | myNode.childNodes = new Array(); |
还是应该使用
我希望答案是直接向上的dom;不过,如果您在jquery中也提供了答案以及dom-only答案,则需要额外的分数。
选项1(速度慢得多,请参阅下面的注释):
1 2 | var myNode = document.getElementById("foo"); myNode.innerHTML = ''; |
选项2(更快):
1 2 3 4 | var myNode = document.getElementById("foo"); while (myNode.firstChild) { myNode.removeChild(myNode.firstChild); } |
当前接受的答案是错误的,因为innerhtml速度较慢(至少在IE和Chrome中),正如M93A正确提到的。
chrome和ff使用此方法的速度显著加快(这将破坏附加的jquery数据):
1 2 | var cNode = node.cloneNode(false); node.parentNode.replaceChild(cNode ,node); |
在远处的一秒钟内出现FF和Chrome,在IE中最快:
1 | node.innerHTML = ''; |
InnerHTML不会破坏事件处理程序或中断jquery引用,这里还建议将其作为解决方案:https://developer.mozilla.org/en-us/docs/web/api/element.innerhtml网站
最快的DOM操作方法(仍然比前两种方法慢)是删除范围,但直到IE9才支持范围。
1 2 3 | var range = document.createRange(); range.selectNodeContents(node); range.deleteContents(); |
上面提到的其他方法似乎具有可比性,但比innerhtml慢得多,除了离群值jquery(1.1.1和3.1.1),它比其他方法慢得多:
1 | $(node).empty(); |
证据如下:
http://jspef.com/innerhtml vs removechild/167http://jspef.com/innerhtml vs removechild/300https://jspef.com/remove-all-child-elements-of-a-dom-node-in-javascript(因为编辑旧的URL不起作用,所以jsper重新启动的新URL)
JSperf的"每个测试循环"通常被理解为"每个迭代",只有第一个迭代有要删除的节点,所以结果是无意义的,在发布时,这个线程中的测试设置不正确。
1 2 3 4 5 6 7 | var myNode = document.getElementById("foo"); var fc = myNode.firstChild; while( fc ) { myNode.removeChild( fc ); fc = myNode.firstChild; } |
如果您有任何机会让jquery影响后代,那么您必须使用一些方法来清理jquery数据。
1 | $('#foo').empty(); |
jquery
如果只使用
如果使用jquery:
1 | $('#foo').empty(); |
如果你不这样做:
1 2 | var foo = document.getElementById('foo'); while (foo.firstChild) foo.removeChild(foo.firstChild); |
使用现代的javascript,与
1 2 3 4 | const parent = document.getElementById("foo"); while (parent.firstChild) { parent.firstChild.remove(); } |
这是一种在ES5中写入节点删除的新方法。它是普通的JS,读起来比以前的版本好得多。
大多数用户应该有现代的浏览器,或者你可以在需要的时候发泄出来。
浏览器支持-2019年4月93%
最快的…
1 2 3 4 | var removeChilds = function (node) { var last; while (last = node.lastChild) node.removeChild(last); }; |
感谢Andrey Lushnikov提供的jspef.com链接(酷网站!).
编辑:要清楚,firstchild和lastchild在chrome中没有性能差异。上面的答案显示了一个很好的性能解决方案。
如果只想让节点不带子节点,也可以这样复制它:
1 | var dupNode = document.getElementById("foo").cloneNode(false); |
取决于你想要达到的目标。
1 | element.textContent = ''; |
除了标准外,它和InnerText很像。它比
另一种方法是:
1 2 3 4 5 6 7 8 9 10 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(); } |
作为对丹曼、马顿和马特的回应。克隆一个节点,设置文本在我的结果中确实是一种可行的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | // @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时返回空值。此外,如果需要确保安全,则在添加内容之前节点是空的,这非常有用。考虑下面的用例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | // @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 ); |
当替换元素中的字符串时,我发现这个方法非常有用,如果您不确定节点将包含什么,那么不用担心如何清理混乱,而是从新开始。
我看到人们在做:
1 2 3 | while (el.firstNode) { el.removeChild(el.firstNode); } |
然后有人说使用
不过,我认为这是最快的:
1 2 3 4 | var children = el.childNodes; for (var i=children.length - 1; i>-1; i--) { el.removeNode(children[i]); } |
你怎么认为?
PS:这个话题对我来说是个救命稻草。我的火狐插件被拒绝了,因为我使用了innerhtml。长期以来它一直是一种习惯。然后我发现了这个。实际上我注意到了一个速度差。加载时,innerhtml花了一段时间进行更新,但是addelement会立即更新!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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 } } } |
这将删除元素中的所有节点。
实现这一点有两种选择:
最快():
1 2 3 | while (node.lastChild) { node.removeChild(node.lastChild); } |
备选方案(较慢):
1 2 3 4 5 6 7 | while (node.firstChild) { node.removeChild(node.firstChild); } while (node.hasChildNodes()) { node.removeChild(node.lastChild); } |
以建议的选项为基准
使用范围循环对我来说最自然:
1 2 3 | for (var child of node.childNodes) { child.remove(); } |
根据我在Chrome和Firefox上的测量,它慢了1.3倍。在正常情况下,这也许无关紧要。
通过javascript删除节点子节点的最简单方法
1 2 3 4 5 | var myNode = document.getElementById("foo"); while(myNode.hasChildNodes()) { myNode.removeChild(myNode.lastChild); } |
我通常做的是:
1 2 3 4 5 | HTMLElement.prototype.empty = function() { while (this.firstChild) { this.removeChild(this.firstChild); } } |
和voila,稍后您可以使用以下命令清空任何dom元素:
1 | anyDom.empty() |
InnerText是赢家!http://jspef.com/innerhtml-vs-removechild/133。在所有以前的测试中,父节点的内部dom在第一次迭代时被删除,然后在应用于空的div时被innerhtml或removechild删除。
通常,javascript使用数组来引用dom节点列表。因此,如果您有兴趣通过htmlelements数组来实现这一点,那么这将很好地工作。另外,值得注意的是,因为我使用的是数组引用,而不是javascript协议,这应该在任何浏览器中都可以使用,包括IE。
1 2 3 | while(nodeArray.length !== 0) { nodeArray[0].parentNode.removeChild(nodeArray[0]); } |
为什么我们不按照最简单的方法来"删除"这个循环。
1 2 3 4 | const foo = document.querySelector(".foo"); while (foo.firstChild) { foo.firstChild.remove(); } |
- 选择父分区
- 在while循环中使用"remove"方法来消除第一个子元素,直到没有剩余元素为止。
刚刚看到有人在另一个问题中提到这个问题,并认为我会添加一个我还没有看到的方法:
1 2 3 4 5 6 | function clear(el) { el.parentNode.replaceChild(el.cloneNode(false), el); } var myNode = document.getElementById("foo"); clear(myNode); |
clear函数接受元素,并使用父节点将其自身替换为不带子节点的副本。如果元素是稀疏的,则性能增益不大,但是当元素具有多个节点时,性能增益就实现了。
最简单的方法:
1 2 | let container = document.getElementById("containerId"); container.innerHTML =""; |
仅仅是IE:
1 | parentElement.removeNode(true); |
jquery中的其他方法
1 2 3 4 5 6 | var foo = $("#foo"); foo.children().remove(); or $("*", foo ).remove(); or foo.html(""); |
简单快速的循环使用!!
1 2 3 4 5 | var myNode = document.getElementById("foo"); for(var i = myNode.childNodes.length - 1; i >= 0; --i) { myNode.removeChild(myNode.childNodes[i]); } |
这在
如果你想把东西放回那个
我的例子:
1 2 3 4 5 6 7 8 9 10 11 12 | <ul> </ul> function displayHTML(result){ var movieLink = document.createElement("li"); var t = document.createTextNode(result.Title); movieLink.appendChild(t); outputDiv.appendChild(movieLink); } |
如果我使用
这是一个纯粹的javascript,我不使用jquery,但在所有浏览器中都可以使用,甚至是IE,而且非常容易理解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | <p> Paragraph one </p> <p> Paragraph two </p> <p> Paragraph three </p> <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 =""; }) |
使用jQuery:
1 | $("#foo").find("*").remove(); |