Eventos JavaScript: Capturing e Bubbling

Manipular eventos JavaScript faz parte do dia-a-dia de qualquer programador front end. Mas você sabe como eventos em JavaScript realmente funcionam?

Ir para o artigo

Manipular eventos JavaScript faz parte do dia-a-dia de qualquer programador front end e é tarefa banal.

Mas você saber como eventos em JavaScript realmente funcionam? 🤔

Um exemplo de Eventos JavaScript

Talvez tudo o que você (pensava que) sabia sobre como eventos JavaScript funcionam esteja errado. Então, prepara-se para ter seu mundo abalado!

Para a demonstração, suponha uma hierarquia simples de elementos: 3 div aninhadas, cada uma com sua respectiva classe, “one”, “two” e “three”.

A aparência disso não é tão importante, mas, se quiser acompanhar mais visualmente, assista ao vídeo no início do artigo.

Usando um loop simples de JavaScript, um evento de click será associado a cada uma dessas div.

Todas as div agora possuem um evento de click associado (para mostrar o nome de sua classe no console). Isso é muito importante para entender o restante.

Ao seu clicar na div mais interna, .three, o que você acha que vai ser logado no console?

  1. one
  2. two
  3. three

Acertou quem pensou:

Exatamente, as 3 classes serão logadas!

Se você não entendeu o motivo disso, nesse ponto, é preciso explicar como as coisas realmente funcionam quando um evento JavaScript é disparado.

Eventos JavaScript: como as coisas realmente funcionam

Quando um evento JavaScript é acionado, existem 2 fases associadas:

  1. Capturing (Captura)
  2. Bubbling (“Borbulhamento” ou Propagação)

Fase de Capturing (Fase 1)

Por padrão, o evento de click (assim como quase todos os outros eventos em JavaScript) não acontece exatamente a partir do elemento que foi clicado.

Ao invés disso, o evento começa no nó root (window) e vai descendo por toda a hierarquia DOM até chegar no elemento em questão (o target).

Essa é a chamada Fase de Capturing ou Captura (ou Fase 1).

Eventos JavaScript: esquematização de como o evento click começa no elemento root, window.

Nisso que ele vai passando por cada um dos elementos da hierarquia, caso haja algum evento do mesmo tipo respectivamente associado, esse evento será disparado.

Eventos JavaScript: esquematização da Fase de Capturing.

Fase de Bubbling (Fase 2)

Depois de percorrer todo esse caminho e finalmente encontrar o target, você acha que ele para? Não, não, não… Ele faz o caminho inverso pela mesma hierarquia até retornar ao elemento root (window).

Esse retorno é a chamada “Fase 2”, mais conhecida como Fase de Bubbling ou “Borbulhamento”.

Mas um outro nome é Fase de Propagação, em um certo sentido até mais condizente ao que acontece. O que é “Propagar”? É difundir; divulgar; espalhar… E é justamente isso que acontece.

Nesse caminho de volta ao root, novamente, se houver algum evento do mesmo tipo respectivamente associado a algum elemento da hierarquia, esse evento será disparado.

Eventos JavaScript: esquematização da Fase de Bubbling.

É por isso que, no exemplo, foi logado “three, two, one”, nessa ordem: dentro dessa hierarquia do aninhamento das div, na Fase de Bubbling primeiro ele disparou o evento da div mais interna, depois da central e, por fim, da mais externa.

Opções para Event Listeners

Na sintaxe mais atual de JavaScript, é admitido um objeto como 3º parâmetro de addEventListener para informar opções relacionadas a esse listener.

Uma dessas opções é capture: true, que alteraria o código-exemplo para:

Essa opção significa que se está querendo trabalhar com o evento na Fase de Captura (como sugere o próprio nome da opção). Então, agora, ao se clicar na div mais interna, será logado:

Já que, na hierarquia, é disparado o evento click do elemento mais externo para o mais interno! 🤯

Como interromper a propagação de um evento JavaScript

O JavaScript também oferece uma maneira de ter um controle mais acurado dessa dinâmica de eventos, permitindo interromper a propagação de eventos.

Alterando a opção capture para seu default false, faça-se um acréscimo à função que faz o log da classe:

Com isso, ao se clicar em qualquer um dos elementos, ele vai logar unicamente a respectiva classe do que foi clicado, já que a propagação foi interrompida.

Então, diz aí: o que vai acontecer ao se usar o stopPropagation() juntamente com capture: true?

Para saber a resposta, assista o vídeo no início do artigo até o final. ;)