O que é evento borbulhando e capturando?

Qual é a diferença entre bubbling e captura de events? Dos dois, qual é o modelo mais rápido e melhor para usar?

   

Borbulhamento e captura de evento são duas formas de propagação de evento na API do HTML DOM, quando um evento ocorre em um elemento dentro de outro elemento e ambos os elementos registraram um identificador para esse evento. O modo de propagação de evento determina em qual ordem os elementos recebem o evento .

Com o borbulhamento, o evento é primeiro capturado e manipulado pelo elemento mais interno e depois propagado para os elementos externos.

Com a captura, o evento é capturado primeiro pelo elemento mais externo e propagado para os elementos internos.

A captura também é chamada de “trickling”, que ajuda a lembrar a ordem de propagação:

goteje para baixo, borbulhe

Nos velhos tempos, a Netscape defendia a captura de events, enquanto a Microsoft promoveu o borbulhar de events. Ambos fazem parte do padrão W3C Document Object Model Events (2000).

O IE <9 usa apenas eventos borbulhando , enquanto o IE9 + e todos os principais navegadores suportam ambos. Por outro lado, o desempenho do borbulhamento de eventos pode ser um pouco menor para DOMs complexos.

Podemos usar o addEventListener(type, listener, useCapture) para registrar os manipuladores de events no modo bubbling (padrão) ou de captura. Para usar o modelo de captura, passe o terceiro argumento como true .

Exemplo

 

Na estrutura acima, suponha que um evento de clique tenha ocorrido no elemento li .

Ao capturar o modelo, o evento será tratado pelo div primeiro (os manipuladores de events de clique no div serão acionados primeiro), depois no ul , finalmente, no último no elemento de destino, li .

No modelo borbulhante, ocorrerá o oposto: o evento será tratado primeiro pelo li , depois pelo ul e, finalmente, pelo elemento div .

Para mais informações, veja

  • Ordem do Evento no QuirksMode
  • addEventListener no MDN
  • Eventos Avançados no QuirksMode

No exemplo abaixo, se você clicar em qualquer um dos elementos destacados, poderá ver que a fase de captura do stream de propagação do evento ocorre primeiro, seguida pela fase de bubbling.

 var logElement = document.getElementById('log'); function log(msg) { logElement.innerHTML += ('

' + msg + '

'); } function capture() { log('capture: ' + this.firstChild.nodeValue.trim()); } function bubble() { log('bubble: ' + this.firstChild.nodeValue.trim()); } var divs = document.getElementsByTagName('div'); for (var i = 0; i < divs.length; i++) { divs[i].addEventListener('click', capture, true); divs[i].addEventListener('click', bubble, false); }
 p { line-height: 0; } div { display:inline-block; padding: 5px; background: #fff; border: 1px solid #aaa; cursor: pointer; } div:hover { border: 1px solid #faa; background: #fdd; } 
 
1
2
3
4
5

Descrição:

quirksmode.org tem uma boa descrição disso. Em poucas palavras (copiado do quirksmode):

Captura de evento

Quando você usa captura de evento

  | | ---------------| |----------------- | element1 | | | | -----------| |----------- | | |element2 \ / | | | ------------------------- | | Event CAPTURING | ----------------------------------- 

o manipulador de events de element1 é acionado primeiro, o manipulador de events de element2 é acionado por último.

Evento borbulhante

Quando você usa borbulhamento de events

  / \ ---------------| |----------------- | element1 | | | | -----------| |----------- | | |element2 | | | | | ------------------------- | | Event BUBBLING | ----------------------------------- 

o manipulador de events de element2 é acionado primeiro, o manipulador de events de element1 é acionado por último.


O que usar?

Depende do que você quer fazer. Não há melhor. A diferença é a ordem da execução dos manipuladores de events. Na maioria das vezes, será bom triggersr manipuladores de events na fase de bubbling , mas também pode ser necessário dispará-los antes.

Se houver dois elementos, elemento 1 e elemento 2. O elemento 2 está dentro do elemento 1 e nós anexamos um manipulador de events com ambos os elementos, vamos dizer onClick. Agora, quando clicamos no elemento 2, eventHandler para ambos os elementos será executado. Agora aqui a questão é em qual ordem o evento será executado. Se o evento anexado ao elemento 1 for executado primeiro, ele será chamado de captura de evento e, se o evento anexado ao elemento 2 for executado primeiro, isso será chamado de bubbling de evento. De acordo com o W3C, o evento começará na fase de captura até atingir o alvo, retornando ao elemento e então começará a borbulhar

Os estados de captura e ebulição são conhecidos pelo parâmetro useCapture do método addEventListener

eventTarget.addEventListener (tipo, ouvinte, [, useCapture]);

Por padrão, useCapture é falso. Isso significa que está na fase de bubbling.

 var div1 = document.querySelector("#div1"); var div2 = document.querySelector("#div2"); div1.addEventListener("click", function (event) { alert("you clicked on div 1"); }, true); div2.addEventListener("click", function (event) { alert("you clicked on div 2"); }, false); 
 #div1{ background-color:red; padding: 24px; } #div2{ background-color:green; } 
 
div 1
div 2

Eu encontrei este tutorial em javascript.info para ser muito claro na explicação deste tópico. E seu resumo de 3 pontos no final está realmente falando com os pontos cruciais. Cito aqui:

  1. Os events primeiro são capturados até o destino mais profundo e, em seguida, aparecem. No IE <9, eles apenas borbulham.
  2. Todos os manipuladores trabalham no estágio de bubbling, exceto addEventListener com o último argumento true, que é a única maneira de capturar o evento no estágio de captura.
  3. Borbulhar / capturar pode ser interrompido por event.cancelBubble = true (IE) ou event.stopPropagation () para outros navegadores.

Há também a propriedade Event.eventPhase , que pode dizer se o evento está no destino ou vem de outro lugar.

Observe que a compatibilidade do navegador ainda não foi determinada. Eu testei no Chrome (66.0.3359.181) e Firefox (59.0.3) e é suportado lá.

Expandindo o já ótimo snippet da resposta aceita , essa é a saída usando a propriedade eventPhase

 var logElement = document.getElementById('log'); function log(msg) { if (logElement.innerHTML == "

No logs

") logElement.innerHTML = ""; logElement.innerHTML += ('

' + msg + '

'); } function humanizeEvent(eventPhase){ switch(eventPhase){ case 1: //Event.CAPTURING_PHASE return "Event is being propagated through the target's ancestor objects"; case 2: //Event.AT_TARGET return "The event has arrived at the event's target"; case 3: //Event.BUBBLING_PHASE return "The event is propagating back up through the target's ancestors in reverse order"; } } function capture(e) { log('capture: ' + this.firstChild.nodeValue.trim() + "; " + humanizeEvent(e.eventPhase)); } function bubble(e) { log('bubble: ' + this.firstChild.nodeValue.trim() + "; " + humanizeEvent(e.eventPhase)); } var divs = document.getElementsByTagName('div'); for (var i = 0; i < divs.length; i++) { divs[i].addEventListener('click', capture, true); divs[i].addEventListener('click', bubble, false); }
 p { line-height: 0; } div { display:inline-block; padding: 5px; background: #fff; border: 1px solid #aaa; cursor: pointer; } div:hover { border: 1px solid #faa; background: #fdd; } 
 
1
2
3
4
5