¿Qué devuelven los métodos querySelectorAll y getElementsBy *?

151

¿ getElementsByClassNameFuncionan (y funciones similares como getElementsByTagNamey querySelectorAll) lo mismo getElementByIdo devuelven una matriz de elementos?

La razón por la que pregunto es porque estoy tratando de cambiar el estilo de todos los elementos usando getElementsByClassName. Vea abajo.

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

//works
document.getElementById('myIdElement').style.size = '100px';
dmo
fuente
37
La pista está, en gran medida, en el nombre: getElementsByClassName()implica un plural, mientras que getElementById()implica un elemento de elemento singular.
David dice que reinstale a Mónica
1
Entiendo eso, simplemente no tenía sentido para mí que no pueda cambiar todos los elementos con ese nombre de clase usando el código anterior en lugar de tener que recorrer una matriz. jquery way es mucho mejor, solo tenía curiosidad acerca de js way
dmo
1
También puede ser útil: stackoverflow.com/questions/3871547/…
kapa

Respuestas:

152

Su getElementById()código funciona ya que los ID deben ser únicos y, por lo tanto, la función siempre devuelve exactamente un elemento (o nullsi no se encontró ninguno).

Sin embargo, getElementsByClassName(), querySelectorAll(), y otros getElementsBy*métodos devuelven una colección array-como de elementos. Iterar sobre él como lo haría con una matriz real:

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

Si prefiere algo más corto, considere usar jQuery :

$('.myElement').css('size', '100px');
ThiefMaster
fuente
1
¿ <iframe>
Eso
3
Es 2018 ... Simplemente cree una función de contenedor para querySelectorAll()y puede tener un código corto agradable sin una gran dependencia de la vieja escuela. qSA(".myElement").forEach(el => el.style.size = "100px")Tal vez haga que el contenedor reciba una devolución de llamada. qSA(".myElement", el => el.style.size = "100px")
2
"Si prefiere algo más corto, considere agregar una gran biblioteca a su proyecto" Sé que 2012 fue un momento diferente, pero incluso entonces habría encontrado que esa parte es ridícula.
CoryCoolguy
1
" Itere sobre él como lo haría con una matriz real ... Cuidado, getElementsByClassName devuelve una NodeList en vivo que podría modificarse inesperadamente durante el ciclo, por ejemplo, si se elimina el nombre de clase por el que fueron seleccionados. ;-)
RobG
20

Está utilizando una matriz como objeto, la diferencia entre getElementbyIdy getElementsByClassNamees que:

  • getElementbyIddevolverá un objeto Element o nulo si no se encuentra ningún elemento con la ID
  • getElementsByClassNamedevolverá una colección HTMLC en vivo , posiblemente de longitud 0 si no se encuentran elementos coincidentes

getElementsByClassName

El getElementsByClassName(classNames)método toma una cadena que contiene un conjunto desordenado de tokens únicos separados por espacios que representan clases. Cuando se llama, el método debe devolver un NodeListobjeto vivo que contenga todos los elementos del documento que tengan todas las clases especificadas en ese argumento, habiendo obtenido las clases dividiendo una cadena en espacios. Si no hay tokens especificados en el argumento, entonces el método debe devolver una NodeList vacía.

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

getElementById

El método getElementById () accede al primer elemento con la identificación especificada.

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

en su código las líneas:

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

será NO funcionan como se esperaba, debido a que la getElementByClassNamedevolverá una matriz y la matriz será NO tener la stylepropiedad, se puede acceder a cada elementiterando a través de ellos.

Es por eso que la función getElementByIdfuncionó para usted, esta función devolverá el objeto directo. Por lo tanto, podrá acceder a la stylepropiedad.

Alvaro Joao
fuente
Tenga en cuenta que las especificaciones whatwg que están implementando los navegadores difieren de las w3c aquí, los primeros (y, por lo tanto, los navegadores actuales) devuelven una colección HTMLC para getElementsByClassName, no una NodeList. Menor, pero puede confundir a algunos.
Kaiido
@ Kaiido, ¿la diferencia práctica es ...? Según tengo entendido, una NodeList es una colección genérica de elementos DOM y está disponible en cualquier DOM, no solo un DOM HTML (por ejemplo, un DOM XML), mientras que una Colección HTMLC es para DOM HTML (obviamente). La única diferencia que puedo ver es el método namedItem de una colección HTMLC .
RobG
PS Nit pick: enlace para WHATWG HTML Living Standard y el estándar W3C HTML 5.2 . Echado a perder por elección. ;-) Sin embargo, no hay diferencia en el punto que planteaste.
RobG
@RobG NodeList tiene muchos métodos que no son accesibles en HTMLCollection.
Kaiido
@ Kaiido: claro, pero forEach no se especifica como parte de la interfaz para colección o NodeList por W3C o WHATWG, se especifica por separado, por ejemplo, como una propiedad de colecciones genéricas en la especificación IDL web, por lo que debería aplicarse tanto a colecciones como a NodeLists (aunque acepto su punto de que la colección devuelta por getElementsByClassName no tiene un método forEach ). Supongo que la conclusión es que hay suficiente historia para una buena respuesta para contarla. :-)
RobG
11

La siguiente descripción se toma de esta página :

El método getElementsByClassName () devuelve una colección de todos los elementos en el documento con el nombre de clase especificado, como un objeto NodeList.

El objeto NodeList representa una colección de nodos. Se puede acceder a los nodos por números de índice. El índice comienza en 0.

Sugerencia: Puede usar la propiedad de longitud del objeto NodeList para determinar la cantidad de elementos con un nombre de clase específico, luego puede recorrer todos los elementos y extraer la información que desee.

Entonces, como parámetro getElementsByClassNameaceptaría un nombre de clase.

Si este es tu cuerpo HTML:

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

luego var menuItems = document.getElementsByClassName('menuItem')devolvería una colección (no una matriz) de los 3 <div>s superiores , ya que coinciden con el nombre de clase dado.

Luego puede iterar sobre esta <div>colección de nodos ( s en este caso) con:

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

Consulte esta publicación para obtener más información sobre las diferencias entre elementos y nodos.

remdevtec
fuente
el bucle se ve mal, debería estar for (var menuItemIndex = 0 ; menuItemIndex < menuItems.length ; menuItemIndex ++) {en mi opinión.
David
11

ES6 proporciona un Array.from()método que crea una nueva instancia de matriz a partir de un objeto iterativo o similar a una matriz.

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>

Como puede ver dentro del fragmento de código, después de usar la Array.from()función, puede manipular cada elemento.


La misma solución usando 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>

usuario amable
fuente
7

En otras palabras

  • document.querySelector()Buscamos solamente el primero uno de los elementos del selector especificado. Por lo tanto, no escupe una matriz, es un valor único. Similar a lo document.getElementById()que obtiene solo elementos de ID, ya que los ID deben ser únicos.

  • document.querySelectorAll()selecciona todos los elementos con el selector especificado y los devuelve en una matriz. Similar a solo document.getElementsByClassName()para clases y document.getElementsByTagName()etiquetas.


¿Por qué usar querySelector?

Se usa simplemente con el único propósito de facilidad y brevedad.


¿Por qué usar getElement / sBy? *

Rendimiento más rápido.


¿Por qué esta diferencia de rendimiento?

Ambas formas de selección tienen el propósito de crear una NodeList para su uso posterior. querySelectors genera una NodeList estática con los selectores, por lo tanto, primero debe crearse desde cero.
getElement / sBy * adapta inmediatamente la NodeList en vivo existente del DOM actual.

Entonces, cuándo usar qué método depende de usted / su proyecto / su dispositivo.


Infos

Demostración de todos los métodos
NodeList Documentation
Performance Test

Thielicious
fuente
4

Devuelve una lista de tipo Array.

Haces de eso una matriz como ejemplo

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

Puede obtener un solo elemento ejecutando

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

pero va a funcionar para el primer elemento con la clase .myElement.

Si desea aplicar esto para todos los elementos con la clase, le sugiero que use

document.querySelectorAll('.myElement').forEach(function(element) {
    element.style.size = '100px';
});
Sergey
fuente
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
Irina Mityugova
fuente
0

Con ES5 + (cualquier navegado hoy en día - 2017) debería poder hacer

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

Matas Vaitkevicius
fuente
0

Una respuesta para el caso específico de Drenzii ...

Puede hacer una función que funcione para cualquiera de los wordelementos y pasar el número del que desea transformar, como:

// 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>

Gato
fuente