Delegação de eventos: ouvindo eventos de forma eficiente

Descubra uma técnica para gerenciar eventos em múltiplos elementos de forma otimizada.

Você já aprendeu a usar addEventListener em elementos específicos.
Agora imagine uma lista com 100 botões de remover.
Adicionar 100 listeners funciona… mas não é o jeito mais eficiente.

É aqui que entra a delegação de eventos.

Ideia principal

Em vez de colocar um listener em cada filho, você coloca um listener no elemento pai e trata os cliques dos filhos usando o objeto event.

Analogia simples:
em vez de um segurança por porta, você coloca um segurança na entrada principal observando quem entrou e o que fez.


Por que isso funciona?

Porque os eventos no DOM “sobem” na árvore (isso se chama propagação/bubbling).

Exemplo:

  • clicou no botão
  • evento acontece no botão
  • depois sobe para o li
  • depois sobe para o ul
  • depois para elementos acima…

Então, se o pai está ouvindo clique, ele consegue detectar cliques dos filhos.


Exemplo sem delegação (menos eficiente)

const botoes = document.querySelectorAll(".btn-remover");

botoes.forEach(function (botao) {
  botao.addEventListener("click", function () {
    botao.parentElement.remove();
  });
});

Problema: se novos botões forem criados depois, eles não terão listener automaticamente.


Exemplo com delegação (mais eficiente)

HTML:

<ul id="lista">
  <li>Item 1 <button class="btn-remover">Remover</button></li>
  <li>Item 2 <button class="btn-remover">Remover</button></li>
</ul>

JavaScript:

const lista = document.getElementById("lista");

lista.addEventListener("click", function (e) {
  if (e.target.matches(".btn-remover")) {
    const item = e.target.closest("li");
    item.remove();
  }
});

O que está acontecendo?

  • O listener está no ul (lista)
  • e.target diz onde o clique realmente aconteceu
  • matches(".btn-remover") verifica se foi no botão certo
  • closest("li") encontra o item da lista para remover

Vantagens da delegação

  • Menos listeners no código
  • Melhor organização
  • Melhor desempenho em listas grandes
  • Funciona com elementos criados dinamicamente depois

Cuidados importantes

  • Sempre filtre com matches ou closest, para não reagir a cliques errados.
  • Escolha um pai adequado (nem amplo demais, nem específico demais).
  • Em estruturas complexas, teste bem para evitar efeitos inesperados.

Mini exemplo com itens dinâmicos

Mesmo se você adicionar novos itens depois, o listener no pai continua funcionando:

const novoItem = document.createElement("li");
novoItem.innerHTML = 'Item novo <button class="btn-remover">Remover</button>';
lista.appendChild(novoItem);

Não precisa adicionar novo addEventListener no botão recém-criado.


Resumo da lição

  • Delegação de eventos = ouvir no pai e tratar no filho.
  • Funciona graças à propagação (bubbling).
  • Use e.target, matches e closest para identificar o alvo correto.
  • Excelente para listas, tabelas, menus e elementos dinâmicos.
  • É uma técnica essencial para código mais eficiente e escalável.