Fluxo de Eventos, Captura, Borbulhamento e Delegação no DOM

Fluxo de Eventos no DOM

Quando um evento ocorre, ele se propaga pelos elementos da árvore DOM em uma ordem específica. Esse processo é chamado de fluxo de eventos DOM e é dividido em três fases:

  1. Fase de captura
  2. Fase de alvo
  3. Fase de borbulhamento

Em um documento HTML aninhado, um evento gerado em um elemento filho viaja do nó raiz (document) até o elemento alvo e depois retorna. Durante a captura, o evento desce do elemento mais externo (document) até o elemento alvo. No alvo, a função de tratamento é executada. No borbulhamento, o evento sobe do elemento alvo de volta ao documento.

Observações importantes:

  • Código JavaScript só pode executar uma das fases (captura ou borbulhamento) por evento.
  • Prorpiedades como onclick e attachEvent só operam na fase de borbulhamento.
  • O método addEventListener(type, listener, useCapture): se useCapture for true, o listener é chamado na fase de captura; caso contrário (padrão false), na fase de borbulhamento.
  • Na prática, o borbulhamento é mais utilizado (captura não é suportada por IE antigo).
  • Eventos como focus, blur, mouseenter e mouseleave não borbulham.

O Objeto Evento

O objeto event (ou e) é passado automaticamente para a função de tratamento. Ele contém informações sobre o evento ocorrido. Para compatibilidade com navegadores antigos (IE 6-8), usa-se window.event.

event = event || window.event;

Propriedades e Métodos Comuns

Propriedade/Método Descrição
e.target Elemento que disparou o evento (padrão W3C).
e.srcElement Equivalente não padrão usado no IE antigo.
e.type Tipo do evento (ex.: "click", "mouseover").
e.cancelBubble Propriedade não padrão para interromper o borbulhamento (IE).
e.returnValue Propriedade não padrão para prevenir ação padrão (IE).
e.preventDefault() Método padrão para prevenir ação padrão.
e.stopPropagation() Método padrão para interromper a propagação (borbulhamento/captura).

Diferença entre this e e.target

  • this refere-se ao elemento ao qual o listener foi vinculado.
  • e.target refere-se ao elemento que realmente originou o evento.
const lista = document.querySelector('ul');
lista.addEventListener('click', function(e) {
  console.log(this);      // <ul>...
  console.log(e.target);  // <li> clicado
});

Prevenindo Ação Padrão

Três formas de impedir o comportamento padrão (ex.: seguir um link):

  • e.preventDefault(); – padrão moderno.
  • e.returnValue = false; – para IE antigo.
  • return false; – funciona em todos, mas encerra a função imediatamnete.

Interrompendo a Propagação

const pai = document.querySelector('.pai');
const filho = document.querySelector('.filho');
pai.addEventListener('click', mostrarNome, false);
filho.addEventListener('click', mostrarNome, false);
document.addEventListener('click', function() {
  alert('Document');
}, false);

function mostrarNome(event) {
  alert(this.className);
  event.stopPropagation();   // interrompe o borbulhamento
  // event.cancelBubble = true; // para IE 6-8
}

Delegação de Eventos

A delegação de eventos consiste em anexar um único listener a um elemanto pai, em vez de adicionar listeners a cada filho. O evento de um filho borbulha até o pai, onde o listener captura o e.target para identificar o elemento clicado.

Por que usar?

  • Reduz o número de listeners, melhorando a performance, especialmente com muitos elementos.
  • Menos manipulação do DOM, evitando reflow e repaint desnecessários.
  • Funciona para elementos adicionados dinamicamente após a vinculação do evento.

Exemplo Prático

Considere uma lista não ordenada:

<ul id="minhaLista">
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
</ul>

Abordagem comum (ineficiente): adicionar um evento mouseover a cada li.

document.querySelectorAll('#minhaLista li').forEach(function(item) {
  item.addEventListener('mouseover', function() {
    this.style.backgroundColor = 'gray';
    // ... resetar irmãos
  });
});

Com delegação: ouvir o evento no ul e identificar o item.

document.getElementById('minhaLista').addEventListener('mouseover', function(e) {
  if (e.target.tagName === 'LI') {
    // Remove destaque de todos os itens
    this.querySelectorAll('li').forEach(function(li) {
      li.style.backgroundColor = '';
    });
    e.target.style.backgroundColor = 'gray';
  }
});

Assim, mesmo que novos itens sejam adicionados dinamicamente, eles herdam o comportamento.

Tags: DOM Eventos captura borbulhamento delegação

Publicado em 7-11 09:05