【问题标题】:forEach does not access all elements in NodeListforEach 不会访问 NodeList 中的所有元素
【发布时间】:2018-12-16 01:38:51
【问题描述】:

由于现在可以在 NodeList 上调用 forEach 数组方法。我想知道为什么如果您在使用forEach 循环时更改childNodes NodeList 的内容,forEach 不会检测到更改。

grid.childNodes.forEach(function(tableRow, index, nodeList) {
  tableRow.remove();
});

在这里,我试图遍历我的表(网格)元素子元素并从表中删除每个子元素(tableRow)。但是,forEach 永远不会完全循环每个元素,总是将最后一个 tableRow 遗漏为removed我认为这与 childNodes NodeList 处于活动状态有关,并且 forEach 无法正确遵循它或某物。

【问题讨论】:

  • 你的相关 html 是什么? grid 的选择器是什么?
  • @DavidThomas const grid = document.querySelector("table");
  • 你知道你可以做grid.innerHTML = "",对吧?
  • 我猜测部分问题是元素子元素 parentNode.children 的数量不等于 parentNode.childNodes 的数量。

标签: javascript dom foreach child-nodes


【解决方案1】:

这是因为,在较低级别,.forEach() 仍在保持计数并使用元素的索引。当您删除一些时,您将从数组/节点列表的开头删除它们,然后索引器变得不准确,因为所有元素索引都必须向下移动一个。例如,以前位于索引位置 5 的元素现在位于索引位置 4。

对于这样的事情,最好使用计数循环并从最后一个索引开始删除元素并向后工作。这将在循环期间保持适当的计数,因为不会修改元素到索引的映射。

这是一个例子:

let grid = document.getElementById("myTable");
document.querySelector("input").addEventListener("click", function(){
  for(i = grid.childNodes.length-1; i > -1; i--) {
    grid.removeChild(grid.childNodes[i]);
  }
});
<table id="myTable">
 <tr>
   <td>Row 1</td>
 </tr>
 <tr>
   <td>Row 2</td>
 </tr>
 <tr>
   <td>Row 3</td>
 </tr>
 <tr>
   <td>Row 4</td>
 </tr>
 <tr>
   <td>Row 5</td>
 </tr> 
</table>

<input type="button" value="Delete Rows">

现在,如果您要使用 DOM Table API.deleteRow()

,也可以使这更简单一些

let grid = document.getElementById("myTable");
document.querySelector("input").addEventListener("click", function(){
  for(i = grid.rows.length-1; i > -1; i--) {
    grid.deleteRow(i);
  }
});
<table id="myTable">
 <tr>
   <td>Row 1</td>
 </tr>
 <tr>
   <td>Row 2</td>
 </tr>
 <tr>
   <td>Row 3</td>
 </tr>
 <tr>
   <td>Row 4</td>
 </tr>
 <tr>
   <td>Row 5</td>
 </tr> 
</table>

<input type="button" value="Delete Rows">

当然,您可以通过清除 .innerHTML 来清除表中的所有内容。

let grid = document.getElementById("myTable");
document.querySelector("input").addEventListener("click", function(){      
    grid.innerHTML = "";
});
<table id="myTable">
 <tr>
   <td>Row 1</td>
 </tr>
 <tr>
   <td>Row 2</td>
 </tr>
 <tr>
   <td>Row 3</td>
 </tr>
 <tr>
   <td>Row 4</td>
 </tr>
 <tr>
   <td>Row 5</td>
 </tr> 
</table>

<input type="button" value="Delete Rows">

【讨论】:

  • 为什么要从最后一个索引开始?
  • @ObayanjuDamilare 我已经在答案中解释了这一点。从头开始删除时,曾经是索引的元素(例如 5)变为索引 4 - 元素映射的索引被丢弃。但是当你从最后删除时,这不会发生。
  • @ObayanjuDamilare 您仍然可以使用.forEach.remove,方法是使用Array.from(grid.childNodes) 而不是grid.childNodes。数组不会像 NodeLists 和 HTMLCollections 那样跟踪哪些元素仍然是 DOM 的一部分。值得注意的是,.childNodes 产生 live NodeList(意味着当子节点发生变化时它会发生变化)与其他返回 NodeList 的方法不同。 HTMLCollections 始终是实时列表。
  • @ScottMarcus 感谢您抽出宝贵时间。我理解你的解释,代码现在可以正常工作了。
  • 完成@ScottMarcus
猜你喜欢
  • 2013-01-12
  • 2020-09-12
  • 1970-01-01
  • 2010-10-19
  • 2015-07-23
  • 1970-01-01
  • 2019-09-01
  • 2019-01-17
  • 1970-01-01
相关资源
最近更新 更多