我有一个段落元素的集合.有些是空的,有些只包含空格,有些则有内容:
<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();
}
没有错误,但并未删除所有元素.所以我再次运行它,它删除了之前未删除的一些元素.我再次运行它,最后从文档中删除所有段落.
我想知道我在这里缺少什么明显的细节.
Fel*_*ing 25
问题是这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文档.
为了说明这个问题,我们假设我们有一个包含三个元素的节点列表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不会删除它,因为它被跳过.
删除项目时,HTMLCollection的长度会发生变化.一种方法是使用while循环
while(paragraphs.length > 0) {
   paragraphs[0].remove();
}
当您删除节点时,HTMLCollection正在发生变化(更改),长度与HTMLCollection数组的“实际”长度不同步。
假设您有一个包含 2 个 DOM 节点的数组,并且正在迭代它。它应该迭代 2 次。下面的演示完美地说明了这一点并且很容易理解:
第一次迭代- 删除第一个节点,然后i递增。
第二次迭代- 现在i等于,1但paragraphs.length现在也1因为此时只剩下一个段落。
这会导致一种不可能的情况,即1要求长度为 的数组访问位置 处的项目1,而唯一可用的位置是0(因为数组从位置开始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>在下面的演示中,节点的删除是在所有迭代周期完成后 进行的(延迟代码执行),这里的关键是利用第三个参数并传递将被缓存的节点作为超时回调的参数: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>| 归档时间: | 
 | 
| 查看次数: | 15903 次 | 
| 最近记录: |