如何正确迭代getElementsByClassName

Kup*_*pto 77 html javascript dom

我是Javascript初学者.

我正在通过它创建网页window.onload,我必须通过类名(slide)找到一堆元素,并根据某些逻辑将它们重新分配到不同的节点.我有一个函数Distribute(element),它将一个元素作为输入并进行分配.我想做这样的事情(例如这里这里所概述的):

var slides = getElementsByClassName("slide");
for(var i = 0; i < slides.length; i++)
{
   Distribute(slides[i]);
}
Run Code Online (Sandbox Code Playgroud)

然而这对我来说并没有什么魔力,因为getElementsByClassName实际上并没有返回数组,而是a NodeList,这是......

......这是我的推测......

...在函数Distribute内部被更改(在此函数中正在更改DOM树,并且发生某些节点的克隆).For-each循环结构也没有帮助.

变量幻灯片的行为确实是非确定性的,通过每次迭代,它都会大大改变元素的长度和顺序.

在我的情况下迭代NodeList的正确方法是什么?我在考虑填充一些临时阵列,但我不知道该怎么做......

编辑:

我忘了提到的重要事实是,在另一个内部可能有一个幻灯片,这实际上是slides由于用户Alohci我刚刚发现的变量.

我的解决方案是先将每个元素克隆到一个数组中,Distribute()然后逐个传递数组.

Alb*_*ing 104

根据MDN,从a检索项目的方法NodeList是:

nodeItem = nodeList.item(index)
Run Code Online (Sandbox Code Playgroud)

从而:

var slides = document.getElementsByClassName("slide");
for(var i = 0; i < slides.length; i++)
{
   Distribute(slides.item(i));
}
Run Code Online (Sandbox Code Playgroud)

我自己没试过(正常的for循环一直对我有用),但是试一试.

  • `for ... of` 允许您现在像在 `for(slide of slides)Distribute(slide)` 中迭代 NodeList。浏览器支持是不完整的,但如果你正在转译,那么 `for ... of` 将被转换,但 `NodeList.forEach` 不会。 (3认同)

sty*_*yks 51

如果您使用新的querySelectorAll,则可以直接调用forEach.

document.querySelectorAll('.edit').forEach(function(button) {
    // Now do something with my button
});
Run Code Online (Sandbox Code Playgroud)

根据以下评论.nodeLists没有forEach函数.

如果使用babel你可以添加Array.from它,它会将非节点列表转换为forEach数组.Array.from在IE 11下面的浏览器本身不起作用.

Array.from(document.querySelectorAll('.edit')).forEach(function(button) {
    // Now do something with my button
});
Run Code Online (Sandbox Code Playgroud)

在昨晚的聚会上,我发现了另一种处理没有forEach的节点列表的方法

[...document.querySelectorAll('.edit')].forEach(function(button) {
    // Now do something with my button
});
Run Code Online (Sandbox Code Playgroud)

浏览器支持[...]

显示为节点列表

显示为节点列表

显示为数组

显示为数组

  • 问题是nodeLists在每个浏览器中都没有forEach函数.如果你愿意修改原型,那么它很简单:`if(!NodeList.prototype.forEach){NodeList.prototype.forEach = Array.prototype.forEach;}` (4认同)

Tee*_*emu 11

2021 年的最新答案

当提出这个问题时(2013 年),.getElementsBy*方法返回一个NodeList。然而,在 2021 年情况并非如此,所有这些 DOM 遍历方法都会返回一个实时的HTMLCollection

这两个列表之间存在显着差异。HTMLCollection 有两个方法,而 NodeList 有五个方法,包括NodeList.forEach,可用于遍历 NodeList。

实时收藏是有问题的,因为没有办法在幕后保持更新。为了实现可靠的集合,HTMLCollection 的每个当前实现中,每次访问集合时都会遍历 DOM。实际上,这意味着,每次访问实时集合的成员(包括长度)时,浏览器都会遍历整个文档以查找特定元素。

标准说:

如果集合是活动的,则该对象上的属性和方法必须对实际的底层数据进行操作,而不是对数据的快照进行操作。

永远不要迭代实时 HTMLCollection!

相反,将集合转换为数组,然后迭代该数组。或者更确切地说,使用 获取元素.querySelectorAll,它为您提供静态 NodeList 和更灵活的选择元素的方式。

如果您确实需要元素的实时列表,请使用最接近的可能的共同祖先元素作为上下文而不是document.

值得注意的是,还存在实时 NodeList。一个实时 NodeList 的例子是Node.childNodes


小智 11

2022 年更新

最快且最短的解决方案

[...document.getElementsByClassName('className')].forEach(el => {
    // Do something with each element
})
Run Code Online (Sandbox Code Playgroud)

为什么它有效?

迭代实时 HTML 集合效率极低

正如上面styks的回答中提到的,[...htmlCollection]将类集合转换为数组。有必要将其转换为数组,因为直接迭代实时 HTMLCollection 效率极低。正如teemu上面所写的“永远不要迭代实时 HTMLCollection! ”:

实时集合存在问题,因为无法在幕后保持集合更新。为了实现可靠的集合,在 HTMLCollection 的每个当前实现中,每次访问集合时都会遍历 DOM。实际上,这意味着每次访问实时集合的成员(包括长度)时,浏览器都会遍历整个文档以查找特定元素。

为什么它是最快、最有效的?

请注意,使用[...arr] 是将 htmlCollection 转换为数组的最快且最有效的方法。harpo制作的所有方法的性能比较可以在这里找到: http ://jsben.ch/h2IFA

(请参阅此处有关 htmlCollection 转换为数组的所有详细信息)


And*_*rew 9

你总是可以使用数组方法:

var slides = getElementsByClassName("slide");
Array.prototype.forEach.call(slides, function(slide, index) {
    Distribute(slides.item(index));
});
Run Code Online (Sandbox Code Playgroud)


ayj*_*jay 7

我遵循Alohci建议的反向循环,因为它是一个现场nodeList.这就是我为那些好奇的人所做的......

  var activeObjects = documents.getElementsByClassName('active'); // a live nodeList

  //Use a reverse-loop because the array is an active NodeList
  while(activeObjects.length > 0) {
    var lastElem = activePaths[activePaths.length-1]; //select the last element

    //Remove the 'active' class from the element.  
    //This will automatically update the nodeList's length too.
    var className = lastElem.getAttribute('class').replace('active','');
    lastElem.setAttribute('class', className);
  }
Run Code Online (Sandbox Code Playgroud)