javascript 从 DOM 中移除 HTMLCollection 元素
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23988982/
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
Removing HTMLCollection elements from the DOM
提问by Marc Kline
I have a collection of paragraph elements. Some are empty and some contain whitespace only, while others have content:
我有一个段落元素的集合。有些是空的,有些只包含空格,而有些则有内容:
<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p>
<p></p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
I'm using getElementsByTagName
to select them:
我getElementsByTagName
用来选择它们:
var paragraphs = document.getElementsByTagName('p');
This returns all paragraphs in the document. I want to remove all of them, so I'd like to run
这将返回文档中的所有段落。我想删除所有这些,所以我想运行
for (var i = 0, len = paragraphs.length; i < len; i++) {
paragraphs[i].remove();
}
but I get Uncaught TypeError: Cannot read property 'remove' of undefined
errors. I think this is strange, but figure I'll try adding a guard and see what happens:
但我收到Uncaught TypeError: Cannot read property 'remove' of undefined
错误。我认为这很奇怪,但我想我会尝试添加一个守卫,看看会发生什么:
for (var i = 0, len = paragraphs.length; i < len; i++) {
paragraphs[i] && paragraphs[i].remove();
}
No error, but not all elements are removed. So I run it again, and it removes someof the elements which weren't removed previously. I run it againand finallyall of the paragraphs are removed from the document.
没有错误,但并非所有元素都被删除。所以我再次运行它,它删除了一些以前没有删除的元素。我再次运行它,最后所有段落都从文档中删除。
I'm wondering what obvious detail I'm missing here.
我想知道我在这里遗漏了什么明显的细节。
回答by Felix Kling
The problem is that paragraphs
is a live list. By removing a p
element, you are also changing that list. A simple fix is to iterate over the list in reverse order:
问题是这paragraphs
是一个实时列表。通过删除一个p
元素,您也在更改该列表。一个简单的解决方法是以相反的顺序遍历列表:
for (var i = paragraphs.length - 1; i >= 0; --i) {
paragraphs[i].remove();
}
The alternative solution is to create a static list(non-live list). You can do this by either:
另一种解决方案是创建一个静态列表(非活动列表)。您可以通过以下任一方式执行此操作:
converting the list into an
Array
:var paragraphs = Array.prototype.slice.call(document.getElementsByTagName('p'), 0);
using
document.querySelectorAll
:var paragraphs = document.querySelectorAll('p');
将列表转换为
Array
:var paragraphs = Array.prototype.slice.call(document.getElementsByTagName('p'), 0);
var paragraphs = document.querySelectorAll('p');
You can then iterate over the list in regular order (using a for
loop):
然后,您可以按常规顺序遍历列表(使用for
循环):
for (var i = 0; i < paragraphs.length; ++i) {
paragraphs[i].remove();
}
or (using a for...of
loop):
或(使用for...of
循环):
for (var paragraph of paragraphs) {
paragraph.remove();
}
Note that .remove
is a relatively new DOM method, and not supported in every browser. See the MDN documentationfor more info.
请注意,这.remove
是一种相对较新的 DOM 方法,并非每个浏览器都支持。有关更多信息,请参阅MDN 文档。
To illustrate the problem, let's imagine we have a node list of three elements, paragraphs = [p0, p1, p2]
. Then this is what happens when you iterate over the list:
为了说明这个问题,让我们假设我们有一个包含三个元素的节点列表,paragraphs = [p0, p1, p2]
。那么当您遍历列表时会发生以下情况:
i = 0, length = 3, paragraphs[0] == p0 => paragraphs = [p1, p2]
i = 1, length = 2, paragraphs[1] == p2 => paragraphs = [p1]
i = 2, length = 1, END
So in this example, p1
is not deleted because it is skipped.
所以在这个例子中,p1
没有被删除,因为它被跳过了。
回答by aljgom
The length of your HTMLCollection changes when you remove an item. A way to do it is to use a while loop
当您删除一个项目时,您的 HTMLCollection 的长度会发生变化。一种方法是使用 while 循环
while(paragraphs.length > 0) {
paragraphs[0].remove();
}
回答by vsync
Why this doesn't work for you:
为什么这对您不起作用:
The HTMLCollectionis mutating (changing) while you are removing nodes, the the length gets out-of-syncwith the "real" length of the HTMLCollectionarray.
所述的HTMLCollection被突变(改变),而要卸下节点,则该长度变外的同步与的“真正的”长度的HTMLCollection阵列。
Lets say you have an array of 2 DOM nodes, and you are iterating it. it should iterate 2 times. The demo below illustrate this perfectly and i easy to follow:
假设您有一个包含 2 个 DOM 节点的数组,并且您正在对其进行迭代。它应该迭代2次。下面的演示完美地说明了这一点,我很容易理解:
first iteration- removes the first node and then i
is incremented.
second iteration- now i
equals to 1
but the paragraphs.length
is now also 1
because only one paragraph is left at this point.
第一次迭代- 删除第一个节点,然后i
递增。
第二次迭代- 现在i
等于1
但paragraphs.length
现在也是1
因为此时只剩下一个段落。
This results in an impossible scenario where an array with length of 1
is asked to access an item at position 1
, and the only position available is 0
(since Arrays startfrom position 0
...)
这导致了一个不可能的场景,其中长度为 的数组1
被要求访问位于位置的项目,1
唯一可用的位置是0
(因为数组从位置开始0
......)
Accessing a position which doesn't exist in an Array (or Array-like object HTMLCollection) is illegal.
访问不存在于数组(或类似数组的对象 HTMLCollection)中的位置是非法的。
var paragraphs = document.getElementsByTagName('p')
for (var i = 0; i <= paragraphs.length; i++) {
console.log(i, paragraphs.length)
paragraphs[i].remove()
}
<p>1</p>
<p>2</p>
Possible fix: delaythe removal of the nodes
可能的解决方法:延迟删除节点
In the below demo the removal of nodes is made afterallcycles of iteration has been made (setTimeout
delays code execution), and the key here is to utilize the third parameter and pass the node which will be cached as the argument for the timeout callback:
在下面的演示中,在所有迭代周期完成后移除节点(setTimeout
延迟代码执行),这里的关键是利用第三个参数并传递将被缓存的节点作为超时回调的参数:
var paragraphs = document.getElementsByTagName('p')
for (var i = 0, len = paragraphs.length; i < len; i++) {
setTimeout(node => node.remove(),0 , paragraphs[i])
}
<p>Pellentesque habitant....</p>
<p></p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
Possible fix: on each iteration check the node exists
可能的解决方法:在每次迭代时检查节点是否存在
Also it's important notto increment i
since the length of the array keeps shrinking, the first item gets removed on every iteration until no more items are left
同样重要的是不要增加,i
因为数组的长度不断缩小,每次迭代都会删除第一个项目,直到没有更多项目剩下
var paragraphs = document.getElementsByTagName('p')
for (var i = 0, len = paragraphs.length; i < len; ) {
if( paragraphs[i] )
paragraphs[i].remove()
}
<p>1</p>
<p>2</p>
<p>3</p>
Possible fix: I would almost always prefer a reverse-iterator
可能的解决方法:我几乎总是更喜欢反向迭代器
var paragraphs = document.getElementsByTagName('p')
for (var i = paragraphs.length; i--; ){
paragraphs[i].remove() // could also use `paragraphs[0]`. "i" index isn't necessary
}
<p>1</p>
<p>2</p>
<p>3</p>
回答by Sebastien C.
You have to use removeChild
on it's parent to do that :
你必须使用removeChild
它的父级来做到这一点:
for (var i = 0, len = paragraphs.length; i < len; i++) {
paragraphs[i].parentNode.removeChild(paragraphs[i]);
}
EDIT : plnkr doesn't seems to run well from here, so I haven't tested, but it should work :
编辑:plnkr 似乎从这里运行得不好,所以我没有测试过,但它应该可以工作:
window.addEventListener("load", function() {
var paragraphs = document.getElementsByTagName('p');
var loop = function() {
for (var i = 0, len = paragraphs.length; i < len; i++) {
paragraphs[i].parentNode.removeChild(paragraphs[i]);
}
};
console.log(paragraphs.length) // 7
loop();
console.log(paragraphs.length) // 3
loop();
console.log(paragraphs.length) // 1
loop();
console.log(paragraphs.length) // 0
});
回答by Bashir Abdelwahed
In my case this was my solution:
就我而言,这是我的解决方案:
var temp = document.getElementsByClassName('level-size');
for (var i = 0, len = temp.length; i < len; i++)
temp[0].remove();
temp[0]because each time I remove it, the hole table is pushed back one index.
temp[0]因为每次我删除它时,孔表都会被推回一个索引。