如何正确迭代getElementsByClassName

时间:2013-04-05 21:07:52

标签: javascript html dom

我是Javascript初学者。

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

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

然而,这对我来说并不神奇,因为getElementsByClassName实际上并不返回数组,而是NodeList,这是...

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

...在函数Distribute内被更改(在此函数中正在更改DOM树,并且发生某些节点的克隆)。 For-each循环结构也无济于事。

变量幻灯片的确非常不确定,通过每次迭代,它都会大大改变元素的长度和顺序。

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

修改

重要的事实我忘了提到另一个幻灯片中可能有一个幻灯片,这实际上是因为用户Alohci我刚刚发现的slides变量的变化。

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

7 个答案:

答案 0 :(得分:88)

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

nodeItem = nodeList.item(index)

因此:

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

我自己没有尝试过(普通for循环对我来说一直都有效),但请试一试。

答案 1 :(得分:42)

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

document.querySelectorAll('.edit').forEach(function(button) {
    // Now do something with my button
});

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

如果将其与babel一起使用,您可以添加Array.from,它会将非节点列表转换为forEach数组。 Array.from在以下浏览器中无法正常工作,包括IE 11.

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

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

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

Browser Support for [...]

显示为节点列表

Showing as Node List

显示为数组

Showing as Array

答案 2 :(得分:8)

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

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

答案 3 :(得分: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);
  }

答案 4 :(得分:7)

2021 年的最新答案

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

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

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

The Standard 说:

<块引用>

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

永远不要迭代实时 HTMLCollection!

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

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

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

答案 5 :(得分:1)

 <!--something like this--> 
<html>
<body>



<!-- i've used for loop...this pointer takes current element to apply a 
 particular change on it ...other elements take change by else condition 
-->  


<div class="classname" onclick="myFunction(this);">first</div>  
<div class="classname" onclick="myFunction(this);">second</div>


<script>
function myFunction(p) {
 var x = document.getElementsByClassName("classname");
 var i;
 for (i = 0; i < x.length; i++) {
    if(x[i] == p)
    {
x[i].style.background="blue";
    }
    else{
x[i].style.background="red";
    }
}
}


</script>
<!--this script will only work for a class with onclick event but if u want 
to use all class of same name then u can use querySelectorAll() ...-->




var variable_name=document.querySelectorAll('.classname');
for(var i=0;i<variable_name.length;i++){
variable_name[i].(--your option--);
}



 <!--if u like to divide it on some logic apply it inside this for loop 
 using your nodelist-->

</body>
</html>

答案 6 :(得分:0)

我在迭代过程中遇到了类似的问题,我登陆了这里。也许其他人也在犯同样的错误。

就我而言,选择器根本不是问题。问题是我弄乱了javascript代码: 我有一个循环和一个子循环。子循环也使用i作为计数器,而不是j,因此,由于子循环覆盖了主循环的i的值,因此该子循环永远无法进行第二次迭代。

var dayContainers = document.getElementsByClassName('day-container');
for(var i = 0; i < dayContainers.length; i++) { //loop of length = 2
        var thisDayDiv = dayContainers[i];
        // do whatever

        var inputs = thisDayDiv.getElementsByTagName('input');

        for(var j = 0; j < inputs.length; j++) { //loop of length = 4
            var thisInput = inputs[j];
            // do whatever

        };

    };