192 votes

Comment itérer correctement dans getElementsByClassName ?

Je suis un débutant en Javascript.

Je suis en train de visiter la page web via le window.onload je dois trouver un groupe d'éléments par leur nom de classe ( slide ) et les redistribuer dans différents nœuds en fonction d'une certaine logique. J'ai la fonction Distribute(element) qui prend un élément en entrée et effectue la distribution. Je veux faire quelque chose comme ceci (comme indiqué par exemple) aquí o aquí ):

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

Cependant, cela ne fait pas la magie pour moi, car getElementsByClassName ne renvoie pas réellement un tableau, mais un NodeList qui est...

...c'est ma spéculation...

...en étant changé de fonction intérieure Distribute (l'arbre DOM est modifié dans cette fonction, et le clonage de certains nœuds se produit). For-each La structure en boucle n'aide pas non plus.

La variable slides agit de manière vraiment indéterminée, à chaque itération, elle change sauvagement de longueur et d'ordre des éléments.

Quelle est la manière correcte d'itérer à travers NodeList dans mon cas ? Je pensais remplir un tableau temporaire, mais je ne suis pas sûr de la façon de le faire...

EDIT :

fait important que j'ai oublié de mentionner est qu'il peut y avoir une diapositive à l'intérieur d'une autre, c'est en fait ce qui change le slides variable comme je viens de le découvrir grâce à l'utilisateur Alohci .

La solution pour moi a été de cloner chaque élément dans un tableau d'abord et de passer le tableau un par un dans Distribute() après.

233voto

Albert Xing Points 2385

Selon MDN la façon d'extraire un élément d'une base de données. NodeList es:

nodeItem = nodeList.item(index)

Ainsi :

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

Je n'ai pas encore essayé moi-même (la méthode normale d'évaluation de l'impact sur l'environnement). for loop a toujours fonctionné pour moi), mais tentez votre chance.

154voto

styks Points 1119

Si vous utilisez le nouveau querySelectorAll, vous pouvez appeler forEach directement.

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

Selon le commentaire ci-dessous, les listes de nœuds n'ont pas de fonction forEach.

Si vous l'utilisez avec babel, vous pouvez ajouter Array.from et il convertira les listes de non nœuds en un tableau forEach. Array.from ne fonctionne pas en mode natif dans les navigateurs inférieurs à et incluant IE 11.

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

Lors de notre réunion d'hier soir, j'ai découvert une autre façon de gérer les listes de nœuds sans forEach.

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

Prise en charge des navigateurs pour [...]

Affichage de la liste des nœuds

Showing as Node List

Affichage sous forme de tableau

Showing as Array

30voto

Teemu Points 11613

Une réponse actualisée en 2021

.getElementsBy* renvoient une HTMLCollection et non un Liste de nœuds , getElementsByName étant une exception.

Il existe des différences remarquables entre ces deux listes. Alors que HTMLCollection possède deux méthodes, NodeList en possède cinq, dont les suivantes NodeList.forEach qui peut être utilisé pour itérer dans une NodeList.

Les collections en direct posent problème car il n'y a aucun moyen de les mettre à jour sous le capot. Pour obtenir une collection fiable, le DOM est traversé à chaque fois qu'on accède à une collection dans toutes les implémentations actuelles de HTMLCollection. En pratique, cela signifie que chaque fois que vous accédez à un membre d'une collection vivante (y compris la longueur), le navigateur parcourt l'ensemble du document pour trouver l'élément spécifique.

La norme dit :

Si une collection est vivante, les attributs et les méthodes de cet objet doivent opérer sur les données sous-jacentes réelles, et non sur un instantané de ces données.

Ne jamais itérer en direct HTMLCollection !

Au lieu de cela, convertissez la collection en tableau, et itérez ce tableau. Ou plutôt, récupérez les éléments en utilisant .querySelectorAll qui vous donne une liste de nœuds statique et un moyen plus souple de sélectionner des éléments.

Si vous avez vraiment besoin d'une liste d'éléments en direct, utilisez l'élément ancêtre commun le plus proche possible comme contexte au lieu de document .

Il est à noter qu'il existe aussi des NodeLists vivantes. Voici des exemples de NodeLists en direct Node.childNodes et la valeur de retour de getElementsByName .

15voto

Andrew Points 131

Vous pouvez toujours utiliser des méthodes de type tableau :

var slides = getElementsByClassName("slide");
Array.prototype.forEach.call(slides, function(slide, index) {
    Distribute(slides.item(index));
});

11voto

lior bakalo Points 65

Mise à jour 2022

La solution la plus rapide et la plus courte

[...document.getElementByClassName('className')].forEach(el => {
    //Do something
})

Pourquoi cela fonctionne-t-il ?

L'itération de la collection HTML en direct est extrêmement inefficace.

Comme mentionné dans stylos Réponse ci-dessus, [...htmlCollection] convertit la collection de classes en un tableau. Il est nécessaire de la convertir en tableau, car l'itération directe d'une collection HTMLCollection vivante serait extrêmement inefficace. Comme teemu a écrit ci-dessus " Ne jamais itérer en direct HTMLCollection ! " :

Les collections en direct posent problème car il n'y a aucun moyen de les mettre à jour sous le capot. Pour obtenir une collection fiable, le DOM est parcouru à chaque fois qu'on accède à une collection, dans chaque implémentation actuelle de HTMLCollection. En pratique, cela signifie que chaque fois que vous accédez à un membre d'une collection vivante (y compris la longueur) le navigateur parcourt l'ensemble du document pour trouver l'élément spécifique.

Pourquoi est-ce le plus rapide et le plus efficace ?

Notez que l'utilisation de [...arr] est le moyen le plus rapide et le plus efficace de convertir htmlCollection en tableau. Une comparaison des performances de toutes les méthodes effectuées par harpo peuvent être trouvés ici : http://jsben.ch/h2IFA

(Voir tous les détails sur la conversion de htmlCollection en tableau. aquí )

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X