152

我是 Javascript 初学者。

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

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

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

……这是我的猜测……

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

可变幻灯片行为真的是不确定的,通过每次迭代它都会疯狂地改变它的长度和元素的顺序。

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

编辑:

我忘了提到的重要事实是,可能有一张幻灯片在另一张幻灯片中,这实际上是改变slides变量的原因,因为我刚刚发现感谢用户Alohci

对我来说,解决方案是先将每个元素克隆到一个数组中,然后将数组一个接一个地传入Distribute()

4

8 回答 8

185

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

nodeItem = nodeList.item(index)

因此:

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

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

于 2013-04-05T21:30:28.923 回答
112

如果您使用新的 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
});

浏览器支持 [...]

显示为节点列表

显示为节点列表

显示为数组

显示为数组

于 2016-08-25T13:14:29.407 回答
20

2021 年的最新答案

当这个问题被问到(2013 年)时,.getElementsBy*方法返回了一个NodeList。但是,在 2021 年情况并非如此,所有这些 DOM 遍历方法都返回一个实时HTMLCollectiongetElementsByName这是一个例外。

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

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

该标准说:

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

永远不要迭代实时 HTMLCollection!

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

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

值得注意的是,还存在实时 NodeList。实时 NodeList 的示例是Node.childNodesgetElementsByName的返回值。

于 2021-03-04T17:43:52.617 回答
12

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

var slides = getElementsByClassName("slide");
Array.prototype.forEach.call(slides, function(slide, index) {
    Distribute(slides.item(index));
});
于 2016-03-28T21:58:25.980 回答
8

我遵循了 Alohci的反向循环的建议,因为它是 live 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);
  }
于 2014-07-17T21:03:36.870 回答
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>
于 2017-12-17T17:28:23.730 回答
1

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

就我而言,选择器根本不是问题。问题是我弄乱了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

        };

    };
于 2020-07-15T16:11:11.203 回答
1

您可以使用Object.values+for...of循环:

const listA = document.getElementById('A');
const listB = document.getElementById('B');
const listC = document.getElementById('C');
const btn = document.getElementById('btn');

btn.addEventListener('click', e => {
  // Loop & manipulate live nodeLList
  for (const li of Object.values(listA.getElementsByClassName('li'))) {
    if (li.classList.contains('active')) {
      listB.append(li);
    } else {
      listC.append(li);
    }
  }
});
ul {
  display: inline-flex;
  flex-direction: column;
  border: 1px solid;
}

ul::before {
  content: attr(id);
}

.active {
  color: red;
}

.active::after {
  content: " (active)";
}
<ul id="A">
  <li class="li active">1. Item</li>
  <li class="li">2. Item</li>
  <li class="li">3. Item</li>
  <li class="li active">4. Item</li>
  <li class="li active">5. Item</li>
  <li class="li">6. Item</li>
  <li class="li active">7. Item</li>
  <li class="li">8. Item</li>
</ul>

<button id="btn">Distribute A</button>

<ul id="B"></ul>
<ul id="C"></ul>

单线:
Object.values(listA.getElementsByClassName('li')).forEach(li => (li.classList.contains('active') ? listB : listC).append(li))
于 2021-12-19T19:33:30.360 回答