So durchlaufen Sie getElementsByClassName korrekt

100

Ich bin Javascript-Anfänger.

Ich starte eine Webseite über die window.onload, ich muss eine Reihe von Elementen anhand ihres Klassennamens ( slide) finden und sie basierend auf einer bestimmten Logik auf verschiedene Knoten verteilen. Ich habe eine Funktion, Distribute(element)die ein Element als Eingabe nimmt und die Verteilung übernimmt. Ich möchte so etwas tun (wie zum Beispiel hier oder hier beschrieben ):

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

Dies macht jedoch nicht die Magie für mich, weil getElementsByClassNamenicht tatsächlich Array zurückgibt, sondern ein NodeList, was ...

... das ist meine Spekulation ...

... innerhalb der Funktion geändert werden Distribute(der DOM-Baum wird innerhalb dieser Funktion geändert und das Klonen bestimmter Knoten erfolgt). For-eachSchleifenstruktur hilft auch nicht.

Die variablen Folien wirken wirklich undeterministisch, da sie bei jeder Iteration die Länge und Reihenfolge der Elemente stark ändern.

Was ist in meinem Fall der richtige Weg, um NodeList zu durchlaufen? Ich habe darüber nachgedacht, ein temporäres Array zu füllen, bin mir aber nicht sicher, wie ich das machen soll ...

BEARBEITEN:

Eine wichtige Tatsache, die ich vergessen habe zu erwähnen, ist, dass sich möglicherweise eine Folie in einer anderen befindet. Dies ändert tatsächlich die slidesVariable, wie ich gerade dank Benutzer Alohci herausgefunden habe .

Die Lösung für mich bestand darin, jedes Element zuerst in ein Array zu klonen und das Array anschließend einzeln zu übergeben Distribute().

Kupto
quelle
3
Dies ist eigentlich der Weg, um es zu tun, also müssen Sie etwas anderes durcheinander bringen!
Adeneo
Die Distribute()Funktion ist zu lang und komplex, um hier kopiert zu werden, aber ich bin sicher, dass ich die DOM-Struktur im Inneren ändere und dort auch Elemente dupliziere (klone). Wenn ich es debugge, kann ich sehen, dass sich die Variablen slidesjedes Mal ändern, wenn sie übergeben werden.
Kupto
Es ändert sich nur, wenn Sie es tatsächlich irgendwo ändern.
Adeneo
5
Ich glaube, dass dies getElementsByClassName()ein Live zurückgibt. Wenn nodeListalso Elemente mit dieser Klasse hinzugefügt werden, nodeListändert sich die Länge der Änderungen, über die Sie iterieren.
David sagt, Monica am
2
@ Kupto-Looping in umgekehrter Reihenfolge löst häufig diese Art von Problem, bei dem die Distribute-Funktion das Element entfernt oder so verschiebt, dass es nicht mehr mit dem Aufruf von getElementsByClassName übereinstimmt, aus dem von David Thomas angegebenen Grund.
Alohci

Antworten:

129

Laut MDN ist der Weg, um ein Element von einem abzurufen , NodeList:

nodeItem = nodeList.item(index)

So:

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

Ich habe es nicht selbst versucht (die normale forSchleife hat immer für mich funktioniert), aber probieren Sie es aus.

Albert Xing
quelle
Dies ist die richtige Lösung, es sei denn, Sie versuchen, Elemente nachzuschlagen und zu ändern, die dieselbe Klasse haben und sich ineinander befinden. Ich habe meine Problemumgehung in Bearbeitung zu meiner Frage erklärt.
Kupto
Sicher, habe das nicht berücksichtigt.
Albert Xing
Warum ist es so, wenn ich fragen darf? Warum ist es nicht implementiert, damit Sie über die Knoten wie folgt iterieren können for(var el in document.getElementsByClassName("foo")){}?
Nearoo
3
for ... ofermöglicht es Ihnen, jetzt wie in über NodeList zu iterieren for (slide of slides) Distribute(slide). Die Browserunterstützung ist lückenhaft, aber wenn Sie transpilieren, for ... ofwird sie konvertiert, NodeList.forEachwürde es aber nicht.
Mr5o1
67

Wenn Sie den neuen querySelectorAll verwenden, können Sie forEach direkt aufrufen.

document.querySelectorAll('.edit').forEach(function(button) {
    // Now do something with my button
});

Gemäß dem Kommentar unten. nodeLists haben keine forEach-Funktion.

Wenn Sie dies mit babel verwenden, können Sie hinzufügen Array.fromund es werden Nicht-Knotenlisten in ein forEach-Array konvertiert. Array.fromfunktioniert nicht nativ in Browsern unten und einschließlich IE 11.

Array.from(document.querySelectorAll('.edit')).forEach(function(button) {
    // Now do something with my button
});

Bei unserem Treffen gestern Abend habe ich einen anderen Weg gefunden, um mit Knotenlisten umzugehen, die kein forEach haben

[...document.querySelectorAll('.edit')].forEach(function(button) {
    // Now do something with my button
});

Browser-Unterstützung für [...]

Anzeige als Knotenliste

Anzeige als Knotenliste

Als Array anzeigen

Als Array anzeigen

Styks
quelle
4
Gotcha dazu ist, dass NodeLists nicht in jedem Browser eine forEach-Funktion haben. Wenn Sie bereit sind, an Prototypen zu basteln, ist dies einfach genug:if ( !NodeList.prototype.forEach ) {NodeList.prototype.forEach = Array.prototype.forEach;}
Joshcanhelp
Elegante Lösung, wenn ich Ihre Antwort mit dem Kommentar von @joshcanhelp kombiniere. Danke :) Natürlich führt dies nur zu einem Leitungsvorteil mit mehreren Schleifen.
Yarwest
1
Sie sollten dies vermeiden, da dies möglicherweise nicht in allen Browsern funktioniert. Hier ist eine einfache Problemumgehung, die ich verwende und die anscheinend überall perfekt funktioniert: css-tricks.com/snippets/javascript/…
tixastronauta
Ich denke du [...document.getElementsByClassName('.edit')].forEach(function(button) {
meintest
@ wp-overwatch.com Der Punkt wird im Klassennamen nicht benötigt. Die richtige Version sollte sein:[...document.getElementsByClassName('edit')].forEach(function(button) {
MXT
11

Sie können immer Array-Methoden verwenden:

var slides = getElementsByClassName("slide");
Array.prototype.forEach.call(slides, function(slide, index) {
    Distribute(slides.item(index));
});
Andrew
quelle
sehr schöne und schöne Antwort, vielen Dank!
Olga Farber
Was ist verteilen?
Lesolorzanov
7

Ich folgte Alohcis Empfehlung, in umgekehrter Reihenfolge zu schleifen, weil es ein Live ist nodeList. Folgendes habe ich für diejenigen getan, die neugierig sind ...

  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);
  }
Ayjay
quelle
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>
Kushal Desai
quelle
0

Ich hatte ein ähnliches Problem mit der Iteration und bin hier gelandet. Vielleicht macht auch jemand anderes den gleichen Fehler wie ich.

In meinem Fall war der Selektor überhaupt nicht das Problem. Das Problem war, dass ich den Javascript-Code durcheinander gebracht hatte: Ich hatte eine Schleife und eine Unterschleife. Die Unterschleife wurde istattdessen auch als Zähler verwendet. jDa die Unterschleife den Wert ider Hauptschleife überschrieb , gelangte diese nie zur zweiten Iteration.

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

        };

    };
J0ANMM
quelle