getElementsByClassName vs querySelectorAll

时间:2014-09-25 20:49:02

标签: javascript

如果我使用

var temp = document.querySelectorAll(".class");
for (var i=0, max=temp.length; i<max; i++) { 
 temp[i].className = "new_class";
}
一切正常。所有节点都会更改其类。 但是,有了gEBCN:

var temp = document.getElementsByClassName("class");
for (var i=0, max=temp.length; i<max; i++) { 
 temp[i].className = "new_class";
}  

我收到错误。代码在某个时刻跳出循环,而不是使用msg“无法将className设置为null”完成作业 我知道这是静态vs live nodelist问题(我认为),但是因为gEBCN要快得多,我需要遍历庞大的节点列表(树),我真的想使用getElementsByClassName。 有什么办法可以坚持使用gEBCN而不是被迫使用querySelectorAll吗?

2 个答案:

答案 0 :(得分:16)

这是因为HTMLCollection返回的getElementsByClassName是有效的。

这意味着如果您将"class"添加到某个元素的classList中,它会神奇地出现在temp中。

对位也是如此:如果删除"class"内的元素的temp类,它将不再存在。

因此,更改类会重新索引集合并更改其长度。所以问题是你预先迭代它的长度,而不考虑索引的变化。

要避免此问题,您可以:

  • 使用非实时收藏。例如,

    var temp = document.querySelectorAll(".class");
    
  • 将实时HTMLCollection转换为数组。例如,使用其中一个

    temp = [].slice.call(temp);
    temp = Array.from(temp); // EcmaScript 6
    
  • 向后迭代。例如,请参阅@Quentin's answer

  • 考虑指数的变化。例如,

    for (var i=0; i<temp.length; ++i) { 
     temp[i].className = "new_class";
     --i; // Subtract 1 each time you remove an element from the collection
    }
    
    while(temp.length) { 
     temp[0].className = "new_class";
    }
    

答案 1 :(得分:9)

在列表后面循环,然后元素将从最后消失(你不再在那里寻找)。

for (var i = temp.length - 1; i >= 0; i--) { 
  temp[i].className = "new_class";
}  

但请注意,IE 8支持querySelectorAll但不支持getElementsByClassName,因此您可能希望更喜欢querySelectorAll以获得更好的浏览器支持。


或者,不要删除现有的课程:

for (var i=0, max=temp.length; i<max; i++) {  
  temp[i].className += " new_class";
}