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()
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 árvorefalse
(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
event.target
vs event.currentTarget
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 encontrarUsar
innerHTML
e recriar elementos pode remover listenersUsar
event.target
sem verificar a tag pode causar erros
✅ Boas práticas
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 clicadoEsquecer que o evento pode subir
Usar muitos listeners sem necessidade (problemas de performance)
Misturar
target
ecurrentTarget
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