2014-09-25 8 views
8

jeśli używamgetElementsByClassName vs querySelectorAll

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

wszystko działa poprawnie. Wszystkie węzły zmieniają swoje klasy. Ale z gEBCN:

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

otrzymuję błąd. Kod przeskakuje z pętli w pewnym momencie, nie kończąc pracy z msg "nie można ustawić className of null".
Rozumiem, że jest to problem statyczny vs żywy węzłów (myślę), ale ponieważ gEBCN jest znacznie szybszy i muszę przejść przez ogromną listę węzłów (drzewo), naprawdę chciałbym użyć getElementsByClassName.
Czy jest coś, co mogę zrobić, aby trzymać się gEBCN i nie być zmuszonym do korzystania z querySelectorAll?

+0

można umieścić demo odtworzyć problem? – elclanrs

Odpowiedz

8

Pętla nad listą w tył, wtedy elementy znikną z końca (gdzie już nie będziesz wyglądać).

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

Należy jednak pamiętać, że IE 8 obsługuje querySelectorAll ale nie getElementsByClassName, więc może chcesz wolą querySelectorAll dla lepszego wsparcia przeglądarki.


Alternatywnie, nie usunąć istniejącą klasę:

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

Dziękuję. Pętla powrotna działa dobrze :). Przyjmuję odpowiedź w 5 min. –

14

to dlatego HTMLCollection zwrócony przez getElementsByClassName jest na żywo.

Oznacza to, że jeśli dodasz "class" do klasy elementów jakiegoś elementu, pojawi się on magicznie w temp.

Odmienna jest również prawdą: jeśli usuniesz klasę "class" elementu wewnątrz temp, nie będzie jej już tam.

Dlatego zmiana klas reindeksuje kolekcję i zmienia jej długość. Problem polega więc na tym, że robisz iterację, chwytając ją wcześniej i nie biorąc pod uwagę zmian indeksów.

Aby uniknąć tego problemu, można:

  • Użyj non kolekcję na żywo. Na przykład,

    var temp = document.querySelectorAll(".class"); 
    
  • Konwersja żywych HTMLCollection do tablicy. Na przykład, z jednym z tychiterować do tyłu. Na przykład zobacz @Quentin's answer.

  • Uwzględnij zmiany indeksów. Na przykład,

    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

(Przed edycjami i nadal istotne dla twierdzenia, że ​​problem jest buforowany 'max'): To nie zadziała. Zatrzyma to działanie, ale będzie pomijać elementy. To zmodyfikuje pierwszy element w indeksie '0' (powodując jego usunięcie z NodeList), następnie zmodyfikuje * trzeci * element, który właśnie przesunął * do indeksu' 1' (pomijając drugi element, który został przesunięty indeksować '0'). – Quentin

+0

@Quentin Yea, uzyskiwałem dziwne wyniki. Niektóre węzły zmieniły klasę, inne nie. –

+0

@Oriol Myślę, że zacofana pętla jest najbardziej eleganckim i najszybszym sposobem na pokonanie problemu z listą spraw. Już przyjąłem odpowiedź Quentina (był szybszy). O querySelectorAll, jest znacznie wolniej pracować, mam treeView z tysiącami węzłów. Reguła gEBCN. –

Powiązane problemy