Page cover

8.10 - Aprofundando nos eventos

🌊 Event Bubbling e Outras Aventuras com Eventos

🌊 Event Bubbling e Outras Aventuras com Eventos

Agora que você já sabe como lidar com eventos, vamos explorar um comportamento mais avançado (e às vezes confuso 😅) chamado event bubbling.

Sim! Os eventos no DOM não agem isoladamente — eles sobem e descem na árvore de elementos da página. Isso é super importante para entender por que às vezes seu evento parece acontecer mais de uma vez ou em lugares que você não esperava.


🌪️ O que é Event Bubbling?

Imagine que você clicou em um botão. Esse botão está dentro de um formulário, que está dentro de uma div, que está dentro do body.

👉 Quando você clica, o evento não para no botão. Ele sobe (bubble) por todos os elementos-pai, até chegar no document.

🧱 Exemplo visual:

<body>
  └── <div>
        └── <form>
              └── <button> ← clique aqui!

Esse clique "borbulha" de baixo para cima: do botão → formulário → div → body → document.


🎯 Exemplo prático

<div id="pai">
  <button id="filho">Clique</button>
</div>

<script>
  document.getElementById("pai").addEventListener("click", () => {
    console.log("Pai clicado!");
  });

  document.getElementById("filho").addEventListener("click", () => {
    console.log("Filho clicado!");
  });
</script>

🔎 Resultado ao clicar no botão:

Filho clicado!
Pai clicado!

Por quê? Porque o clique no botão também chegou no pai. 🧼


⛔ Evitando efeitos colaterais com stopPropagation()

Se você não quiser que o evento suba, use:

element.addEventListener("click", (event) => {
  event.stopPropagation();
});

Isso interrompe a "subida" do evento, evitando que ele acione outros elementos pai.


👀 Event Capturing: O lado oposto do bubbling!

Sabia que o evento também pode ser detectado na descida pela árvore, antes de atingir o elemento?

✨ É o chamado capturing phase (ou fase de captura).

Você ativa isso com um terceiro argumento no addEventListener:

element.addEventListener("click", minhaFuncao, true);

🔄 Comparando:

  • true = captura → detecta o evento descendo a árvore

  • false (padrão) = bubbling → detecta subindo


ℹ️ Curiosidade útil: Por que existem o event bubbling e o event capturing?

Essas fases foram criadas para dar mais controle aos desenvolvedores na forma como os eventos são tratados.

Imagine uma árvore com milhares de elementos. Se cada elemento precisasse de seu próprio "ouvidor de eventos", o desempenho da página seria péssimo e o código ficaria complicado.

✅ O bubbling permite que você trate eventos em elementos-pai com poucas linhas de código, como quando usamos delegação de eventos.

🔍 O capturing é útil quando você quer interceptar o evento antes que ele chegue ao destino (como um guarda que intercepta antes de entrar no prédio).

Ou seja: não é só um detalhe técnico — é uma escolha de arquitetura pensada para performance, flexibilidade e clareza. 😉


🔄 Delegação de eventos (Event Delegation)

Sabia que você pode usar o bubbling a seu favor?

Em vez de colocar um addEventListener em cada item, você pode colocar um só no pai e reagir com base no event.target.

Exemplo:

<ul id="lista">
  <li>Item 1</li>
  <li>Item 2</li>
</ul>

<script>
  document.getElementById("lista").addEventListener("click", (event) => {
    if (event.target.tagName === "LI") {
      console.log("Clicou em:", event.target.textContent);
    }
  });
</script>

🧠 Isso é mais eficiente, especialmente se os itens forem criados dinamicamente!


🧭 event.target vs event.currentTarget

Propriedade
O que representa?

target

Onde o evento aconteceu de fato

currentTarget

Onde o addEventListener foi registrado

Exemplo:

element.addEventListener("click", (event) => {
  console.log("target:", event.target);
  console.log("currentTarget:", event.currentTarget);
});

🕵️ Use target para saber quem foi clicado 🧱 Use currentTarget para saber quem está "ouvindo"


🔁 Comportamentos inesperados comuns

  • Clicar em um botão dispara um evento no form, div, e até body

  • Esquecer de usar stopPropagation() pode causar bugs difíceis de encontrar

  • Usar innerHTML e recriar elementos pode remover listeners

  • Usar event.target sem verificar a tag pode causar erros


✅ Boas práticas

Fazer
Evitar

Usar delegação em listas grandes

Adicionar centenas de listeners

Usar stopPropagation() com propósito claro

Usar stopPropagation() sem motivo (pode quebrar coisas!)

Verificar event.target.tagName ao delegar

Assumir que o clique sempre vem do elemento certo


🚨 Erros comuns para evitar

  • Achar que addEventListener só funciona no elemento clicado

  • Esquecer que o evento pode subir

  • Usar muitos listeners sem necessidade (problemas de performance)

  • Misturar target e currentTarget nos testes


🧪 Teste na prática!

Crie um quadrado dentro de outro quadrado e adicione um click nos dois. Veja quem é chamado primeiro (usando bubbling) e depois inverta usando capturing. Experimente stopPropagation() e use console.log() para estudar o fluxo!

Last updated