O que os métodos querySelectorAll e getElementsBy * retornam?

151

Do getElementsByClassName(e funções semelhantes, como getElementsByTagNamee querySelectorAll) funcionam da mesma forma getElementByIdou eles retornar um array de elementos?

A razão pela qual pergunto é porque estou tentando alterar o estilo de todos os elementos usando getElementsByClassName. Ver abaixo.

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

//works
document.getElementById('myIdElement').style.size = '100px';
dmo
fonte
37
A pista está, em grande parte, no nome: getElementsByClassName()implica um plural, enquanto getElementById()implica um item de elemento singular.
David diz que restabelece Monica
1
Entendi, não fazia sentido para mim que você não pode alterar todos os elementos com esse nome de classe usando o código acima, em vez de ter que percorrer uma matriz. jquery forma é muito melhor, eu estava apenas curioso sobre a forma como js
DMO
1
Pode ser útil também: stackoverflow.com/questions/3871547/…
kapa

Respostas:

152

Seu getElementById()código funciona, pois os IDs precisam ser exclusivos e, portanto, a função sempre retorna exatamente um elemento (ou nullse nenhum foi encontrado).

No entanto, getElementsByClassName(), querySelectorAll(), e outros getElementsBy*métodos de devolver uma colecção matriz semelhante de elementos. Faça uma iteração como você faria com uma matriz real:

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

Se você preferir algo mais curto, considere usar o jQuery :

$('.myElement').css('size', '100px');
ThiefMaster
fonte
1
Isso também se aplicam a <iframe>que também faz parte do seu domínio
JMASTER B
3
É 2018 ... Basta criar uma função de wrapper para querySelectorAll()e você pode ter um código curto agradável sem uma grande dependência da velha escola. qSA(".myElement").forEach(el => el.style.size = "100px")Talvez o wrapper receba um retorno de chamada. qSA(".myElement", el => el.style.size = "100px")
2
"Se você preferir algo mais curto, considere adicionar uma enorme biblioteca ao seu projeto" Eu sei que 2012 foi uma época diferente, mas mesmo assim eu teria achado essa parte ridícula.
CoryCoolguy
1
" Itere como você faria com uma matriz real ... Cuidado, getElementsByClassName retorna um NodeList ao vivo que pode ser inesperadamente modificado durante o loop, por exemplo, se o nome da classe pela qual eles foram selecionados for removido. ;-)
RobG
20

Você está usando uma matriz como objeto, a diferença entre getElementbyIde getElementsByClassNameé que:

  • getElementbyIdretornará um objeto Element ou null se nenhum elemento com o ID for encontrado
  • getElementsByClassNameretornará uma HTMLCollection ativa , possivelmente de comprimento 0, se nenhum elemento correspondente for encontrado

getElementsByClassName

O getElementsByClassName(classNames)método utiliza uma sequência que contém um conjunto não ordenado de tokens exclusivos separados por espaço que representam classes. Quando chamado, o método deve retornar um NodeListobjeto ativo que contém todos os elementos no documento que possuem todas as classes especificadas nesse argumento, tendo obtido as classes dividindo uma string em espaços. Se não houver tokens especificados no argumento, o método deverá retornar um NodeList vazio.

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

getElementById

O método getElementById () acessa o primeiro elemento com o ID especificado.

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

no seu código as linhas:

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

vai NÃO funcionam como esperado, porque o getElementByClassNameirá retornar uma matriz, e a matriz irá NÃO têm a stylepropriedade, você pode acessar cada elementpor iteração através deles.

É por isso que a função getElementByIdfuncionou para você; essa função retornará o objeto direto. Portanto, você poderá acessar a stylepropriedade.

Alvaro Joao
fonte
Observe que as especificações whatwg que estão sendo implementadas pelos navegadores diferem das especificadas no w3c aqui, as primeiras (e, portanto, os atuais) retornam uma HTMLCollection para getElementsByClassName, não uma NodeList. Menor, mas pode confundir alguns.
Kaiido
@ Kaiido - a diferença prática sendo…? Para meu entendimento, um NodeList é uma coleção genérica de elementos DOM e está disponível em qualquer DOM, não apenas em um DOM HTML (por exemplo, um XML DOM), enquanto um HTMLCollection é para DOMs HTML (obviamente). A única diferença que posso ver é o método namedItem de um HTMLCollection .
RobG 18/11/19
Escolha PS Nit: link para o padrão de vida HTML WHATWG e o padrão HTML 5.2 do W3C . Mimado por escolha. ;-) Não faz diferença ao ponto que você levantou.
RobG
O @RobG NodeList possui muitos métodos que não estão acessíveis no HTMLCollection.
Kaiido
@ Kaiido - claro, mas forEach não é especificado como parte da interface para a coleção ou NodeList por W3C ou WHATWG, é especificado separadamente, por exemplo, como uma propriedade de coleções genéricas na especificação IDL da Web, portanto deve ser aplicado a coleções e NodeLists (embora eu aceite seu argumento de que a coleção retornada por getElementsByClassName não possui um método forEach ). Acho que o ponto principal é que há uma história suficiente para uma boa resposta para contar. :-)
RobG 18/11/19
11

A seguinte descrição é retirada desta página :

O método getElementsByClassName () retorna uma coleção de todos os elementos no documento com o nome da classe especificado, como um objeto NodeList.

O objeto NodeList representa uma coleção de nós. Os nós podem ser acessados ​​por números de índice. O índice começa em 0.

Dica: Você pode usar a propriedade length do objeto NodeList para determinar o número de elementos com um nome de classe especificado. Em seguida, você pode percorrer todos os elementos e extrair as informações desejadas.

Portanto, como parâmetro getElementsByClassName, aceitaria um nome de classe.

Se este é o seu corpo HTML:

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

em seguida var menuItems = document.getElementsByClassName('menuItem'), retornaria uma coleção (não uma matriz) dos 3 <div>s superiores , pois eles correspondem ao nome da classe.

Em seguida, você pode iterar sobre essa <div>coleção de nós com este:

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

Consulte este post para obter mais informações sobre as diferenças entre elementos e nós.

remdevtec
fonte
11

O ES6 fornece um Array.from()método, que cria uma nova instância Array a partir de um objeto iterável ou semelhante a uma 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 você pode ver dentro do snippet de código, depois de usar a Array.from()função, você poderá manipular cada elemento.


A mesma solução 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>

usuário gentil
fonte
7

Em outras palavras

  • document.querySelector()selecciona apenas o primeiro um elemento do selector especificado. Portanto, não cuspir uma matriz, é um valor único. Semelhante ao document.getElementById()que busca apenas elementos de ID, pois os IDs precisam ser exclusivos.

  • document.querySelectorAll()seleciona todos os elementos com o seletor especificado e os retorna em uma matriz. Semelhante a apenas document.getElementsByClassName()para classes e document.getElementsByTagName()tags.


Por que usar querySelector?

É usado apenas com o único objetivo de facilidade e brevidade.


Por que usar getElement / sBy? *

Desempenho mais rápido.


Por que essa diferença de desempenho?

As duas formas de seleção têm como objetivo criar um NodeList para uso posterior. querySelectors gera um NodeList estático com os seletores, portanto, ele deve ser criado primeiro do zero.
getElement / sBy * adapta imediatamente o NodeList ativo existente do DOM atual.

Portanto, quando usar qual método depende de você / seu projeto / seu dispositivo.


Informações

Demonstração de todos os métodos
NodeList Documentation
Performance Test

Thielicious
fonte
4

Ele retorna uma lista semelhante a uma matriz.

Você faz disso uma matriz como exemplo

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

Você pode obter um único elemento executando

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

mas funcionará para o primeiro elemento com a classe .myElement.

Se você deseja aplicar isso a todos os elementos da classe, sugiro que você use

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

Com o ES5 + (qualquer navegador atualmente - 2017), você deve poder fazer

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

Matas Vaitkevicius
fonte
0

Uma resposta para o caso específico de Drenzii ...

Você pode criar uma função que funcione para qualquer um dos wordelementos e passe o número daquele que você deseja 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
fonte