我有一系列段落元素。有些是空的,有些只包含空格,有些则有内容:
<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>
我使用getElementsByTagName
选择它们:
var paragraphs = document.getElementsByTagName('p');
这将返回文档中的所有段落。我想删除所有这些,所以我想要运行
for (var i = 0, len = paragraphs.length; i < len; i++) {
paragraphs[i].remove();
}
但我收到Uncaught TypeError: Cannot read property 'remove' of undefined
错误。我觉得这很奇怪,但我想尝试添加一名后卫,看看会发生什么:
for (var i = 0, len = paragraphs.length; i < len; i++) {
paragraphs[i] && paragraphs[i].remove();
}
没有错误,但并非所有元素都被删除。所以我再次运行它,它删除了以前没有删除过的部分元素。我再次运行 ,最后所有段落都从文档中删除。
我想知道我在这里错过了哪些明显的细节。
答案 0 :(得分:22)
问题是paragraphs
是实时列表。通过删除p
元素,您也可以更改该列表。一个简单的解决方法是在逆序中迭代列表:
for (var i = paragraphs.length - 1; i >= 0; --i) {
paragraphs[i].remove();
}
另一种解决方案是创建静态列表(非实时列表)。您可以通过以下任一方式执行此操作:
将列表转换为Array
:
var paragraphs =
Array.prototype.slice.call(document.getElementsByTagName('p'), 0);
var paragraphs = document.querySelectorAll('p');
然后,您可以按常规顺序遍历列表(使用for
循环):
for (var i = 0; i < paragraphs.length; ++i) {
paragraphs[i].remove();
}
或(使用for...of
循环):
for (var paragraph of paragraphs) {
paragraph.remove();
}
请注意,.remove
是一种相对较新的DOM方法,并不是每个浏览器都支持。有关详细信息,请参阅MDN documentation。
为了说明问题,让我们假设我们有一个包含三个元素的节点列表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
因此,在此示例中,p1
未被删除,因为它被跳过。
答案 1 :(得分:7)
删除项目时,HTMLCollection的长度会发生变化。一种方法是使用while循环
while(paragraphs.length > 0) {
paragraphs[0].remove();
}
答案 2 :(得分:1)
当您删除节点时, HTMLCollection 正在变异(更改),其长度与的“实际”长度成为不同步 HTMLCollection 数组。
假设您有2个DOM节点的数组,并且正在对其进行迭代。它应该迭代2次。下面的演示完美地说明了这一点,我很容易理解:
第一次迭代-删除第一个节点,然后递增i
。
第二次迭代-现在i
等于1
,但是paragraphs.length
现在也1
,因为此时只剩下一个段落。>
这将导致一个不可能的情况:要求长度为1
的数组访问位置1
处的项目,并且唯一可用的位置是0
(因为Arrays 从位置0
开始 ...)
访问数组(或类似数组的对象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>
在下面的演示中,在完成所有迭代周期后{em> (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>
另外,重要的是不要递增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>
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>
答案 3 :(得分:0)
您必须在其父级上使用removeChild
来执行此操作:
for (var i = 0, len = paragraphs.length; i < len; i++) {
paragraphs[i].parentNode.removeChild(paragraphs[i]);
}
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
});
答案 4 :(得分:0)
就我而言,这是我的解决方案:
var temp = document.getElementsByClassName('level-size');
for (var i = 0, len = temp.length; i < len; i++)
temp[0].remove();
temp [0] 因为每次删除它都会将孔表推回一个索引。