Que renvoient les méthodes querySelectorAll et getElementsBy *?


151

Faire getElementsByClassName (et des fonctions similaires comme getElementsByTagNameet querySelectorAll) fonctionnent de la même manière getElementByIdou renvoient-elles un tableau d'éléments?

La raison pour laquelle je demande est que j'essaie de changer le style de tous les éléments en utilisant getElementsByClassName. Voir ci-dessous.

//doesn't work
document.getElementsByClassName('myElement').style.size = '100px';

//works
document.getElementById('myIdElement').style.size = '100px';

37
L'indice est, en grande partie, dans le nom: getElementsByClassName()implique un pluriel, alors qu'il getElementById()implique un élément élément singulier.
David dit de réintégrer Monica

1
Je comprends cela, cela n'a pas de sens pour moi que vous ne puissiez pas changer tous les éléments avec ce nom de classe en utilisant le code ci-dessus au lieu d'avoir à parcourir un tableau. jquery way est beaucoup mieux,
j'étais

1
Peut-être aussi utile: stackoverflow.com/questions/3871547/…
kapa

Réponses:


152

Votre getElementById()code fonctionne car les identifiants doivent être uniques et donc la fonction renvoie toujours exactement un élément (ounull si aucun n'a été trouvé).

Cependant, getElementsByClassName(), querySelectorAll()et d' autres getElementsBy*méthodes renvoient une collection semblable à un tableau d'éléments. Répétez dessus comme vous le feriez avec un vrai tableau:

var elems = document.getElementsByClassName('myElement');
for(var i = 0; i < elems.length; i++) {
    elems[i].style.size = '100px';
}

Si vous préférez quelque chose de plus court, envisagez d'utiliser jQuery :

$('.myElement').css('size', '100px');

1
Est-ce que cela s'applique également à <iframe>qui fait également partie de votre domaine
JMASTER B

3
Nous sommes en 2018 ... Il suffit de créer une fonction wrapper pour querySelectorAll()et vous pouvez avoir un joli code court sans une grande dépendance à l'ancienne. qSA(".myElement").forEach(el => el.style.size = "100px")Peut-être que le wrapper recevra un rappel. qSA(".myElement", el => el.style.size = "100px")

2
"Si vous préférez quelque chose de plus court, pensez à ajouter une énorme bibliothèque à votre projet" Je sais que 2012 a été une période différente, mais même dans ce cas, j'aurais trouvé cela ridicule.
CoryCoolguy

1
" Répétez dessus comme vous le feriez avec un vrai tableau… Attention, getElementsByClassName renvoie une NodeList en direct qui pourrait être modifiée de manière inattendue pendant la boucle, par exemple si le nom de classe par lequel ils ont été sélectionnés est supprimé. ;-)
RobG

20

Vous utilisez un tableau comme objet, la différence entre getElementbyIdet getElementsByClassNameest la suivante:

  • getElementbyIdretournera un objet Element ou nul si aucun élément avec l'ID n'est trouvé
  • getElementsByClassNameretournera une HTMLCollection en direct , éventuellement de longueur 0 si aucun élément correspondant n'est trouvé

getElementsByClassName

La getElementsByClassName(classNames)méthode prend une chaîne qui contient un ensemble non ordonné de jetons uniques séparés par des espaces représentant des classes. Lorsqu'elle est appelée, la méthode doit retourner un NodeListobjet vivant contenant tous les éléments du document qui ont toutes les classes spécifiées dans cet argument, après avoir obtenu les classes en divisant une chaîne sur les espaces. Si aucun jeton n'est spécifié dans l'argument, la méthode doit renvoyer une NodeList vide.

https://www.w3.org/TR/2008/WD-html5-20080610/dom.html#getelementsbyclassname

getElementById

La méthode getElementById () accède au premier élément avec l'ID spécifié.

https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById

dans votre code les lignes:

1- document.getElementsByClassName ('myElement'). Style.size = '100px';

ne pas fonctionner comme prévu, parce que la getElementByClassNameretourne un tableau, et le tableau sera pas avoir la stylepropriété, vous pouvez accéder à chaqueelement par itérer à travers eux.

C'est pourquoi la fonction getElementByIda fonctionné pour vous, cette fonction retournera l'objet direct. Par conséquent, vous pourrez accéder à la stylepropriété.


Notez que les spécifications whatwg qui sont implémentées par les navigateurs diffèrent ici de celles du w3c, les anciennes (et donc les navigateurs actuels) renvoient une HTMLCollection pour getElementsByClassName, pas une NodeList. Mineur, mais peut en dérouter certains.
Kaiido

@ Kaiido - la différence pratique étant…? À ma compréhension, une NodeList est une collection générique d'éléments DOM et est disponible dans n'importe quel DOM, pas seulement un DOM HTML (par exemple un DOM XML), alors qu'une HTMLCollection est pour les DOM HTML (évidemment). La seule différence que je peux voir est la méthode namedItem d'un HTMLCollection .
RobG

PS Nit pick: lien vers le standard de vie WHATWG HTML et le standard W3C HTML 5.2 . Gâté par le choix. ;-) Cela ne change rien au point que vous avez soulevé.
RobG

@RobG NodeList a de nombreuses méthodes qui ne sont pas accessibles sur HTMLCollection.
Kaiido

@ Kaiido — bien sûr, mais forEach n'est pas spécifié comme partie de l'interface pour la collection ou NodeList par W3C ou WHATWG, il est spécifié séparément, par exemple en tant que propriété de collections génériques dans la spécification Web IDL et devrait donc s'appliquer aux collections et aux NodeLists (bien que j'accepte votre point de vue selon lequel la collection retournée par getElementsByClassName n'a pas de forEach méthode ). Je suppose que l'essentiel est qu'il y a suffisamment d'histoire pour qu'une bonne réponse puisse la raconter. :-)
RobG

11

La description suivante est tirée de cette page :

La méthode getElementsByClassName () renvoie une collection de tous les éléments du document avec le nom de classe spécifié, sous la forme d'un objet NodeList.

L'objet NodeList représente une collection de nœuds. Les nœuds sont accessibles par numéros d'index. L'index commence à 0.

Conseil: vous pouvez utiliser la propriété length de l'objet NodeList pour déterminer le nombre d'éléments avec un nom de classe spécifié, puis vous pouvez parcourir tous les éléments et extraire les informations souhaitées.

Donc, en tant que paramètre getElementsByClassName accepterait un nom de classe.

S'il s'agit de votre corps HTML:

<div id="first" class="menuItem"></div>
<div id="second" class="menuItem"></div>
<div id="third" class="menuItem"></div>
<div id="footer"></div>

puis var menuItems = document.getElementsByClassName('menuItem')retournerait une collection (pas un tableau) des 3 supérieurs<div> s , car ils correspondent au nom de classe donné.

Vous pouvez ensuite parcourir cette collection de nœuds ( <div>dans ce cas) avec:

for (var menuItemIndex = 0 ; menuItems.length ; menuItemIndex ++) {
   var currentMenuItem = menuItems[menuItemIndex];
   // do stuff with currentMenuItem as a node.
}

Veuillez consulter cet article pour en savoir plus sur les différences entre les éléments et les nœuds.


la boucle semble fausse, devrait être for (var menuItemIndex = 0 ; menuItemIndex < menuItems.length ; menuItemIndex ++) {à mon avis.
David

11

ES6 fournit une Array.from()méthode qui crée une nouvelle instance Array à partir d'un objet de type tableau ou itérable.

let boxes = document.getElementsByClassName('box');

Array.from(boxes).forEach(v => v.style.background = 'green');
console.log(Array.from(boxes));
.box {
  width: 50px;
  height: 50px;
  margin: 5px;
  background: blue;
  display: inline-block;
}
<div class='box'></div>
<div class='box'></div>
<div class='box'></div>
<div class='box'></div>

Comme vous pouvez le voir dans l'extrait de code, après avoir utilisé la Array.from()fonction, vous pouvez alors manipuler chaque élément.


La même solution en utilisant jQuery.

$('.box').css({'background':'green'});
.box {
  width: 50px;
  height: 50px;
  margin: 5px;
  background: blue;
  display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='box'></div>
<div class='box'></div>
<div class='box'></div>
<div class='box'></div>


7

En d'autres termes

  • document.querySelector()sélectionne uniquement la première un élément du sélecteur spécifié. Donc, il ne crache pas un tableau, c'est une valeur unique. Semblable à ce document.getElementById()qui va chercher ID-éléments seulement, étant donné que les ID doivent être uniques.

  • document.querySelectorAll()sélectionne tous les éléments avec le sélecteur spécifié et les renvoie dans un tableau. Similaire à document.getElementsByClassName()pour les classes et les document.getElementsByTagName()balises uniquement.


Pourquoi utiliser querySelector?

Il est utilisé uniquement dans le seul but de facilité et de brièveté.


Pourquoi utiliser getElement / sBy? *

Des performances plus rapides.


Pourquoi cette différence de performance?

Les deux méthodes de sélection ont pour but de créer une liste de nœuds pour une utilisation ultérieure. querySelectors génère une liste de nœuds statique avec les sélecteurs, elle doit donc d'abord être créée à partir de zéro.
getElement / sBy * adapte immédiatement la liste de nœuds en direct existante du DOM actuel.

Alors, quand utiliser quelle méthode c'est à vous / votre projet / votre appareil.


Infos

Démo de toutes les méthodes Test de performance de la
documentation NodeList


4

Il renvoie une liste de type Array.

Vous en faites un tableau comme exemple

var el = getElementsByClassName("elem");
el = Array.prototype.slice.call(el); //this line
el[0].appendChild(otherElem);  

4

Vous pouvez obtenir un seul élément en exécutant

document.querySelector('.myElement').style.size = '100px';

mais cela fonctionnera pour le premier élément avec la classe .myElement.

Si vous souhaitez appliquer ceci pour tous les éléments avec la classe, je vous suggère d'utiliser

document.querySelectorAll('.myElement').forEach(function(element) {
    element.style.size = '100px';
});

4
/*
 * To hide all elements with the same class, 
 * use looping to reach each element with that class. 
 * In this case, looping is done recursively
 */

const hideAll = (className, i=0) => {
if(!document.getElementsByClassName(className)[i]){ //exits the loop when element of that id does not exist
  return; 
}

document.getElementsByClassName(className)[i].style.visibility = 'hidden'; //hide element
return hideAll(className, i+1) //loop for the next element
}

hideAll('appBanner') //the function call requires the class name

0

Avec ES5 + (tout parcouru de nos jours - 2017), vous devriez pouvoir faire

[].forEach.call(document.getElementsByClassName('answer'), function(el) {
    el.style.color= 'red';
});


0

Une réponse au cas spécifique de Drenzii ...

Vous pouvez créer une fonction qui fonctionnera pour n'importe lequel des wordéléments et passer le numéro de celui que vous souhaitez transformer, comme:

// Binds `wordButtons` to an (array-like) HTMLCollection of buttons
const wordButtons = document.getElementsByClassName("word");

// Applies the `slantWord` function to the first word button
slantWord(1);

// Defines the `slantWord` function
function slantWord(wordNumber) {
  const index = wordNumber - 1; // Collection index is zero-based
  wordButtons[index].style.transform = "rotate(7deg)"; // Transforms the specified button
}
<div class="wordGameContainer">
  <button class="word word1">WORD 1</button>
  <button class="word word2">WORD 2</button>
  <button class="word word3">WORD 3</button>
  <button class="word word4">WORD 4</button>
</div>

<div>
  <button onclick="moveWord()" class="playButton">PLAY</button>
</div>

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.