getElementsByClassName与querySelectorAll的区别

15

if I use

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";
}  

我遇到了错误,代码在某个时候跳出循环,没有完成工作,并显示“无法设置空对象的className”消息。
我认为这是静态与动态节点列表的问题,但由于gEBCN更快,而且我需要遍历大量的节点(树),所以我真的想使用getElementsByClassName。
有没有办法让我坚持使用gEBCN而不被迫使用querySelectorAll?

你能发布一个演示来重现这个问题吗? - elclanrs
2个回答

21

这是因为由getElementsByClassName返回的HTMLCollection是动态的。

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

相反的情况也是如此:如果您从temp内部的元素中删除"class"类,则它将不再存在。

因此,更改类会重新索引集合并更改其长度。因此问题在于,您在迭代之前捕获其长度,并且没有考虑到索引的更改。

为避免此问题,您可以:

  • Use a non live collection. For example,

    var temp = document.querySelectorAll(".class");
    
  • Convert the live HTMLCollection to an array. For example, with one of these

    temp = [].slice.call(temp);
    temp = Array.from(temp); // EcmaScript 6
    
  • Iterate backwards. For example, see @Quentin's answer.

  • Take into account the changes of the indices. For example,

    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";
    }
    

那样做是行不通的。它会防止它跑到末尾,但它会在进行操作时跳过一些元素。也就是说,它会修改索引为0的第一个元素(导致它从NodeList中被移除),然后它将修改第三个元素,该元素刚刚移动到索引1(跳过了移动到索引0的第二个元素)。 - Quentin
@Quentin 是的,我得到了一些奇怪的结果。有些节点改变了类别,有些没有改变。 - Wolf War
@Oriol 我认为反向循环是克服livelist问题最优雅和最快的方法。我已经接受了Quentin的答案(他更快)。关于querySelectorAll,它的工作速度要慢得多,我有一个包含数千个节点的treeView。gEBCN规则。 - Wolf War

11

倒序遍历列表,那么元素将从末尾消失(你不再看的地方)。

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";
}  

谢谢。反向循环正常工作:)。我将在5分钟内接受答案。 - Wolf War

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接