7 maneiras de selecionar elementos com Javascript sem querySelectorAll, querySelector e getElementById

Além dos já conhecidos querySelectorAll, querySelector e getElementById, existem essas 7 alternativas para você selecionar elementos na tela usando Javascript.

  • querySelector
  • querySelectorAll
  • dom
  • html
  • javascript
  • document
  • getElementById
  • selecionar elementos
Front-end

Shortcut

Use os atributos document.head, document.body, document.links, document.images, document.forms e document.scripts.

Eles lhe dão acesso direto a alguns elementos.

Ahhh, manipular a DOM, uma das magias do Javascript...

Nessa situação, é muito comum você usar os métodos querySelector, querySelectorAll e getElementById.

Eles são como varas de pesca, que selecionam elementos na tela. E a isca é o argumento que você informa, isso pode ser um ID, classe, atributo ou um seletor excêntrico do CSS.

É importante lembrar que essas alternativas não são milagrosas. Elas não substituem totalmente esses métodos.

Vou falar como eles funcionam, outros métodos conhecidos, e também alternativas a eles.

Mas antes, tenho uma pergunta:

Por que usar alternativas ao querySelectorAll, querySelector e getElementById?

Performance!

Esse é o principal motivo.

Antes de explicar isso, é importante entender como esses 3 métodos funcionam. Todos eles recebem uma string como argumento e retornam um nodelist (não uma array) com os elementos (ou um elemento único) que atendem aos requisitos.

querySelectorAll

Use esse método para pegar vários elementos da DOM.

Ele recebe uma string em formato de seletor CSS e retorna uma nodelist com esses elementos.

A linha document.querySelectorAll('.product-image') busca por todos os elementos com a classe product-image.

Logo, quanto maior a DOM, maior o tempo de execução de cada uso desse método.

Como curiosidade, na data de hoje (14/01/2023), a página inicial do g1.globo.com tem 4.672 itens na DOM.

Se você executasse 3 vezes um document.querySelectorAll, haveria mais de 10 mil verificações de elementos.

Amostra da quantidade de elementos HTML na home do G1: 4672
4672 elementos HTML na home do G1

querySelector

Use esse método para pegar um elemento da DOM.

Esse é bem parecido com o anterior, com uma única diferença: ele retorna apenas o primeiro elemento que atende aos requisitos.

Ao encontrá-lo, esse método pára a sua execução. Assim, ele pode ser mais rápido do que o querySelectorAll. Tudo depende se esse elemento está no início ou no final da DOM.

getElementById

Igual ao anterior, porém seleciona elementos apenas pelo ID.

Dos 3 métodos analisados, esse é o mais rápido, conforme você pode acompanhar nos links no final desse post.

Uma curiosidade é que todos os elementos com um ID são acessíveis através do objeto global window:

mostrar como todo elemento html com id é acessível pelo objeto global window
Elemento HTML com ID acessível pelo objeto global window

Talvez por esse motivo o getElementById seja mais rápido. Pois em vez de escanear toda a DOM, ele pega os elementos direto desse objeto.

Alternativas ao querySelectorAll, querySelector e getElementById

A cabeça da página: document.head

Essa propriedade retorna o elemento <head> da sua página.

Esse elemento agrupa as metatags como:

  • <meta>

  • <link>

  • <script>

  • <title>

  • <style>

Caso você precise buscar alguma delas, pode usar document.head.querySeletor('meta') por exemplo.

Mas por que não usar diretamente document.querySeletor('meta')?

Mais abaixo eu falarei sobre isso.

O corpo da página: document.body

Essa propriedade retorna o elemento <body> da sua página.

Um caso de uso muito comum é bloquear o scroll do site quando um modal é aberto. Nessa situação, o <body> precisa da propriedade CSS overflow:hidden:

function openModal() {
  document.body.style.overflow = 'hidden';
  // other expressions to open modal
  // ...
}

function closeModal() {
  document.body.style.overflow = '';
  // other expressions to close modal
  // ...
}

Essa propriedade retorna um HTML collection com todas as tags <a> da página.

Muito sites configuram os links que apontam para outros domínios para abrirem em uma nova aba. Isso é feito no HTML através do atributo target="_blank".

Se por algum motivo, você só pode fazer isso com Javascript, use o document.links para isso:

const allLinks = Array.from(document.links);

/*
O Array.from() serve para transformar
um HTML collection em uma array.

Assim você pode usar métodos como:

- forEach
- map
- filter
- reduce
- etc
*/

allLinks.forEach(link => {
  if (!link.href.includes('mydomain')) {
    link.target = '_blank';
    // Ou
    link.setAttribute('target', '_blank');
  }
});

As imagens da página: document.images

Essa propriedade retorna um HTML collection com todas as tags <img> da página.

Um caso de uso muito comum é quando você precisa aplicar o efeito de lazyload nas imagens.

Entenda o que é lazyload e como criar esse efeito compatível com todos os navegadores.

Spoiler: é ótimo para performance, SEO e consumo de banda de banda de internet.

Assim, o acesso a essas imagens fica mais rápido:

function setLazyload(imagesList) {
  // Essa função recebe a lista de
  // imagens para aplicar o lazy load
}

const allImages = document.images;

setLazyload(allImages); // Execução da função

Pode ser que você não precise aplicar o lazyload em todas as imagens. E sim apenas naquelas que, por exemplo, possuem a classe .lazy.

Nesse caso, é preciso filtrar a lista de imagens antes de executar a função:

function setLazyload(imagesList) {
  // Essa função recebe a lista de
  // imagens para aplicar o lazy load
}

const allImages = Array.from(document.images);

const imagesToLazyload = allImages.filter(
 image => image.classList.contains('lazy')
);

setLazyload(imagesToLazyload); // Execução da função

Os formulários da página: document.forms

Essa propriedade retorna um HTML collection com todas as tags <form> da página.

Se você tiver apenas um formulário, pode chegar até ele assim document.forms[0].

Caso tenha mais de um, é arriscado usar números maiores que zero, exemplo document.forms[3]. Isso porque se você adicionar um formulário na DOM, o índice de todos eles mudarão nessa lista e podem parar de funcionar.

Você pode usá-lo quando quiser prevenir o comportamento default dos formulários que é recarregar a página:

// Prevenir o comportamento default de todos os forms

Array.from(document.forms).forEach(form => {
  form.addEventListener('submit', event => {
    event.preventDefault();
  });
});

// Depois é só aplicar os outros eventos
// de forma individual normalmente

document.forms[0].addEventListener(
  'submit', () => alert('form 1')
);

document.forms[1].addEventListener(
  'submit', () => alert('form 2')
);

Os scripts da página: document.scripts

Essa propriedade retorna um HTML collection com todas as tags <script> da página.

Imagine que você precise inserir uma tag <script> em uma página, mas só possa fazer isso com Javascript. Muitas libs, por questão de organização, inserem antes da primeira ou após a última tag <script>.

Primeiro, crie a tag:

const scriptTag = document.createElement('script');
scriptTag.type = "text/javascript";
scriptTag.async = 'async';
scriptTag.src = 'https://www.example.com/my-script/'

// A tag script ficará assim:
// 
// <script 
//   type="text/javascript"
//   async="async"
//   src="https://www.example.com/my-script/"
// ></script>

Agora, insira ela na DOM:

// Inserir antes da primeira tag <script> da página
document.scripts[0].insertAdjacentHTML(
  'beforebegin', scriptTag.outerHTML
);

// Inserir depois da última tag <script> da página
Array.from(document.scripts)
  .at(-1) // busca a última tag script da lista
  .insertAdjacentHTML('afterend', scriptTag.outerHTML); // insere após ela

[EXTRA] O título da página: document.title

Essa propriedade retorna o conteúdo em formato de texto que está dentro da tag <title>.

De todos apresentados, é o único que retorna um texto puro, e não um elemento ou lista de elementos HTML.

Limitações dessas alternativas

Nem tudo são flores.

Essas alternativas que mostrei servem apenas para quando você precisa selecionar e mexer em vários elementos. Com exceção, é claro, do document.head, document.body e document.title.

Por isso, dei exemplos onde você altera todas as imagens, links e formulários.

Caso precise mexer em um elemento específico, prefira usar algum dos métodos querySelectorAll, querySelector e getElementById. Caso contrário, dentro do HTML collection de retorno, precisará saber a posição do elemento desejado.

Se essas alternativas não forem o suficiente para o seu caso, está tudo bem.

Existe uma forma de tornar os métodos querySelectorAll e querySelector mais performáticos.

Como melhorar a performance dos métodos querySelectorAll e querySelector

Você deve estar muito acostumado a usar esse método junto com o objeto global document:

document.querySelectorAll('.alguma-coisa');

// Ou

document.querySelector('.alguma-coisa');

A técnica que uso é bem simples:

Faça apenas uma busca na DOM inteira. Isso não significa usar apenas uma vez esses métodos. Você fará a primeira busca por um elemento que envolve todos os outros necessários. Depois disso, as próximas buscas irão iniciar nesse elemento, e não em document.

Por exemplo, a div que envolve todos elementos de um modal possui a classe modal-wrapper:

const modalWrapper = document.querySelector('.modal-wrapper');

Agora, a próxima busca irá iniciar nesse elemento, que foi colocado na constante modalWrapper:

// Busca iniciando em document
const modalWrapper = document.querySelector('.modal-wrapper');

// Busca iniciando modalWrapper
const closeModalButton = modalWrapper.querySelector('.close-modal-button');
const modalTitle = modalWrapper.querySelector('.modal-title');

// ...

A partir do segundo querySelector, a busca não ocorre mais a partir do elemento raiz da DOM. Ele irá acontecer apenas dentro da seção capturada no primeiro querySelector.

Importante: essa técnica irá funcionar apenas com querySelectorAll e querySelector.

Use o método getElementById somente junto com document.

E outros métodos como getElementsByTagName, getElementsByName e getElementsByClassName?

Eles possuem comportamentos muito parecidos.

Assim como os métodos que já expliquei, todos aqui recebem uma string como argumento. Porém eles retornam um HTML collection (e não um nodelist) com os elementos que atendem aos requisitos:

  • getElementsByTagName: recebe o nome de uma tag HTML e retorna os elementos com essa tag

  • getElementsByClassName: recebe uma classe e retorna os elementos com essa classe

  • getElementsByName: recebe um valor e retorna os elementos que possuem esse valor em seu atributo name

Confesso que são métodos pouco usados na prática.

A grande diferença é que eles retornam um HTML collection, e o querySelectorAll retorna um nodelist. Você pode iterar em um nodelist com o método forEach(), o que não é possível fazer num HTML collection. A não ser que você converta para uma array com o método Array.from().

Além disso, o querySelectorAll permite usar seletores mais complexos, como esse:

const links = document.querySelectorAll(
  '.product-cart > img[src*="png"]'
);

Callback

Os métodos querySelectorAll, querySelector e getElementById são indispensáveis para selecionar elementos e manipular a DOM.

Porém tente não abusar do uso deles.

Use atributos como:

  • document.head

  • document.body

  • document.links

  • document.images

  • document.forms

  • document.scripts

Eles ajudarão no momento de selecionar elementos na tela.

Busque elementos na DOM inteira apenas uma vez, para otimizar as buscas.

Lembre-se que essas alternativas possuem limitações.

Por outro lado, se quiser quebrar todas essas regras, fique à vontade. E torne-se o pior front-end da empresa 😄

E aí, já conhecia elas?

Comenta aí!


Continue lendo:

Veja outros posts sobre Front-end