[英]Is there a way to Hide/unhide all child elements of a DOM node in JavaScript?
[英]Remove all child elements of a DOM node in JavaScript
我將如何着手刪除 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 的答案,則可以加分。
innerHTML
。 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>
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>
lastChild
:firstChild
,但已更新為在計算機科學中使用lastChild
,通常,刪除集合的最后一個元素比刪除第一個元素要快得多(取決於集合的方式已實施)。firstChild
以防萬一檢查firstChild
比檢查lastChild
(例如,如果元素列表被 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>
lastElementChild
:Element
(即#text
節點和<!-- comments -->
)的父級(但不是它們的后代)的子級 - 這在您的應用程序中可能是可取的(例如,一些使用內聯 HTML 的模板系統用於存儲模板說明的注釋)。lastElementChild
的支持。 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
原型添加一個新的方法屬性,以簡化對它的調用,只需el.clearChildren()
(其中el
是任何HTML 元素對象)。 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>
replaceChildren()
API! 現在可以使用(支持跨瀏覽器的) replaceChildren
API替換所有子項:
container.replaceChildren(...arrayOfNewChildren);
這將同時做到:
您還可以使用相同的 API 來刪除現有的子項,而不替換它們:
container.replaceChildren();
Chrome/Edge 86+、Firefox 78+ 和 Safari 14+ 完全支持此功能。 這是完全指定的行為。 這可能比這里提出的任何其他方法都要快,因為刪除舊子項和添加新子項是在不需要innerHTML
的情況下完成的,並且是一步而不是多個。
remove
!const parent = document.getElementById("foo")
while (parent.firstChild) {
parent.firstChild.remove()
}
這是在 ES5 中編寫節點刪除的新方法。 它是普通的 JS,比依賴父級讀起來要好得多。
支持所有現代瀏覽器。
瀏覽器支持- 97% 21 年 6 月
正如 m93a 正確提到的那樣,當前接受的關於innerHTML
速度較慢的答案是錯誤的(至少在 IE 和 Chrome 中)。
使用這種方法(這將破壞附加的 jquery 數據),Chrome 和 FF 的速度要快得多:
var cNode = node.cloneNode(false);
node.parentNode.replaceChild(cNode, node);
在 FF 和 Chrome 中遙遙領先,在 IE 中最快:
node.innerHTML = '';
InnerHTML不會破壞您的事件處理程序或破壞 jquery 引用,它也被推薦為這里的解決方案: https ://developer.mozilla.org/en-US/docs/Web/API/Element.innerHTML。
最快的 DOM 操作方法(仍然比前兩種慢)是 Range 刪除,但在 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 (jsperf 重新啟動的新 url,因為編輯舊 url 不起作用)
Jsperf 的“per-test-loop”通常被理解為“per-iteration”,只有第一次迭代有節點要刪除,所以結果沒有意義,在發布時,這個線程中的測試設置不正確。
如果你使用 jQuery:
$('#foo').empty();
如果您不這樣做:
var foo = document.getElementById('foo');
while (foo.firstChild) foo.removeChild(foo.firstChild);
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
方法刪除子項,則該數據將保留。
最快的...
var removeChilds = function (node) {
var last;
while (last = node.lastChild) node.removeChild(last);
};
感謝 Andrey Lushnikov 鏈接到 jsperf.com (很酷的網站!)。
編輯:需要明確的是,在 Chrome 中 firstChild 和 lastChild 之間沒有性能差異。 最佳答案顯示了一個很好的性能解決方案。
使用elm.replaceChildren()
。
它在沒有廣泛支持的情況下是實驗性的,但是在沒有參數的情況下執行時會滿足您的要求,並且比遍歷每個子節點並刪除它更有效。 如前所述,用空字符串替換innerHTML
將需要瀏覽器進行 HTML 解析。
更新它現在被廣泛支持
如果您只想擁有沒有子節點的節點,您也可以像這樣復制它:
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();
}
myNode.querySelectorAll('*').forEach( n => n.remove() );
這回答了問題,並刪除了“所有子節點” 。
如果存在屬於myNode
的文本節點,則無法使用 CSS 選擇器選擇它們,在這種情況下,我們必須應用(也):
myNode.textContent = '';
實際上最后一個可能是最快和更有效/高效的解決方案。
.textContent
比.innerText
和.innerHTML
更有效,參見: MDN
element.textContent = '';
就像innerText,除了標准。 它比removeChild()
慢一點,但它更容易使用,如果你沒有太多要刪除的東西,它不會對性能產生太大影響。
這是我通常做的:
HTMLElement.prototype.empty = function() {
while (this.firstChild) {
this.removeChild(this.firstChild);
}
}
瞧,稍后您可以使用以下命令清空任何 dom 元素:
anyDom.empty()
回應 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 );
這也適用於嘗試訪問 parentNode 時返回 null 的不在 dom 中的節點。 此外,如果您需要確保在添加內容之前節點為空,這確實很有幫助。 考慮下面的用例。
// @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 );
我發現這種方法在替換元素內的字符串時非常有用,如果您不確定節點將包含什么,而不是擔心如何清理混亂,重新開始。
使用范圍循環對我來說是最自然的:
for (var child of node.childNodes) {
child.remove();
}
根據我在 Chrome 和 Firefox 中的測量,它慢了大約 1.3 倍。 在正常情況下,這可能無關緊要。
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
}
}
}
這將刪除元素內的所有節點。
有幾種選擇可以實現這一目標:
最快的 ():
while (node.lastChild) {
node.removeChild(node.lastChild);
}
替代品(較慢):
while (node.firstChild) {
node.removeChild(node.firstChild);
}
while (node.hasChildNodes()) {
node.removeChild(node.lastChild);
}
innerText 是贏家! http://jsperf.com/innerhtml-vs-removechild/133 。 在所有先前的測試中,父節點的內部 dom 在第一次迭代時被刪除,然后將 innerHTML 或 removeChild 應用於空 div。
通過Javascript刪除節點的子節點的最簡單方法
var myNode = document.getElementById("foo");
while(myNode.hasChildNodes())
{
myNode.removeChild(myNode.lastChild);
}
let el = document.querySelector('#el');
if (el.hasChildNodes()) {
el.childNodes.forEach(child => el.removeChild(child));
}
我看到人們在做:
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 會立即更新!
為什么我們不遵循這里最簡單的方法“刪除”在while中循環。
const foo = document.querySelector(".foo");
while (foo.firstChild) {
foo.firstChild.remove();
}
通常,JavaScript 使用數組來引用 DOM 節點列表。 因此,如果您有興趣通過 HTMLElements 數組進行操作,這將很好地工作。 另外,值得注意的是,因為我使用的是數組引用而不是 JavaScript 原型,所以這應該適用於任何瀏覽器,包括 IE。
while(nodeArray.length !== 0) {
nodeArray[0].parentNode.removeChild(nodeArray[0]);
}
剛剛看到有人在另一個中提到這個問題,並認為我會添加一個我還沒有看到的方法:
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 元素中刪除所有子元素。
element.innerHTML = ""
(或 .textContent)是迄今為止最快的解決方案
例如: https ://jsperf.com/innerhtml-vs-removechild/15
此測試不會在每次迭代之間向元素添加新的子元素。 第一次迭代將刪除元素的內容,然后其他所有迭代都不會執行任何操作。 在這種情況下, while (box.lastChild) box.removeChild(box.lastChild)
更快,因為box.lastChild 99% 的時間都是null
這是一個適當的測試: https ://jsperf.com/innerhtml-conspiracy
最后,不要使用node.parentNode.replaceChild(node.cloneNode(false), node)
。 這將用沒有其子節點的自身副本替換節點。 但是,這不會保留事件偵聽器並破壞對節點的任何其他引用。
ES6+ 瀏覽器的最佳移除方法(2016 年后發布的主要瀏覽器):
也許有很多方法可以做到這一點,例如Element.replaceChildren() 。 我想向您展示一個有效的解決方案,它只有一個支持所有 ES6+ 瀏覽器的重繪和重排。
function removeChildren(cssSelector, parentNode){
var elements = parentNode.querySelectorAll(cssSelector);
let fragment = document.createDocumentFragment();
fragment.textContent=' ';
fragment.firstChild.replaceWith(...elements);
}
用法: removeChildren('.foo',document.body);
: 刪除<body>
中所有 className foo
的元素
您可以從容器中刪除所有子元素,如下所示:
function emptyDom(selector){
const elem = document.querySelector(selector);
if(elem) elem.innerHTML = "";
}
現在您可以調用該函數並傳遞選擇器,如下所示:
如果元素有 id = foo
emptyDom('#foo');
如果元素有 class = foo
emptyDom('.foo');
如果元素有標簽 = < div >
emptyDom('div')
如果你想清空整個父DOM
,那么這很簡單......
只需使用.empty()
function removeAll() { $('#parent').empty(); }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <button onclick="removeAll()">Remove all the element of parent</button> <div id="parent"> <h3>Title</h3> <p>Child 1</p> <p>Child 2</p> <p>Child 3</p> </div>
我是這樣做的
data = { "messages": [ [0, "userName", "message test"], [1, "userName1", "message test1"] ] } for (let i = 0; i < data.messages.length; i++) { var messageData = document.createElement('span') messageData.className = 'messageClass' messageData.innerHTML = `${data.messages[i][2]} ${'<br />'}` $(".messages").append(messageData) } $('#removeMessages').on('click', () => { node = $('.messages').get(0) while (node.firstChild) { node.firstChild.remove() } $('#removeMessages').toggle(500) $('#addMessages').toggle(500) }) $('#addMessages').on('click', () => { for (let i = 0; i < data.messages.length; i++) { var messageData = document.createElement('span') messageData.className = 'messageClass' messageData.innerHTML = `${data.messages[i][2]} ${'<br />'}` $(".messages").append(messageData) } $('#addMessages').toggle(500) $('#removeMessages').toggle(500) })
#addMessages{ display:none; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <div class="messages"></div> <button type='button' id="removeMessages">Remove</button> <button type='button' id="addMessages">Add MEssages</button>
從 DOM 中刪除節點的所有子node
的單行代碼
Array.from(node.children).forEach(c => c.remove())
只是IE:
parentElement.removeNode(true);
true
- 表示進行深度移除 - 這意味着所有子項也被移除
我將如何在 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 的答案,則可以加分。
使用 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>
如果我使用.firstChild
或.lastChild
方法,則displayHTML()
函數在之后不起作用,但.innerHTML
方法沒有問題。
這是一個純 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 ="";
})
用 jQuery :
$("#foo").find("*").remove();
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.