getElementsByClassName vs querySelectorAll

后端 未结 2 1837
花落未央
花落未央 2020-11-29 08:30

if I use

var temp = document.querySelectorAll(\".class\");
for (var i=0, max=temp.length; i

        
相关标签:
2条回答
  • 2020-11-29 09:28

    Loop over the list backwards, then elements will vanish from the end (where you aren't looking any more).

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

    Note, however, that IE 8 supports querySelectorAll but not getElementsByClassName, so you might want to prefer querySelectorAll for better browser support.


    Alternatively, don't remove the existing class:

    for (var i=0, max=temp.length; i<max; i++) {  
      temp[i].className += " new_class";
    }  
    
    0 讨论(0)
  • 2020-11-29 09:30

    That's because HTMLCollection returned by getElementsByClassName is live.

    That means that if you add "class" to some element's classList, it will magically appear in temp.

    The oposite is also true: if you remove the "class" class of an element inside temp, it will no longer be there.

    Therefore, changing the classes reindexes the collection and changes its length. So the problem is that you iterate it catching its length beforehand, and without taking into account the changes of the indices.

    To avoid this problem, you can:

    • 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 讨论(0)
提交回复
热议问题