O que é evento borbulhante e captura?

Respostas:

1441

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

Com a bolha, o evento é capturado e tratado primeiro 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 "gotejamento", o que ajuda a lembrar a ordem de propagação:

escorrer, borbulhar

Antigamente, a Netscape defendia a captura de eventos, enquanto a Microsoft promovia a bolha de eventos. Ambos fazem parte do padrão W3C Document Object Model Events (2000).

O IE <9 usa apenas a interferência de eventos , enquanto o IE9 + e todos os principais navegadores oferecem suporte a ambos. Por outro lado, o desempenho de bolhas de eventos pode ser um pouco menor para DOMs complexos.

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

Exemplo

<div>
    <ul>
        <li></li>
    </ul>
</div>

Na estrutura acima, assuma que ocorreu um evento de clique no lielemento

No modelo de captura, o evento será tratado pelo divprimeiro (clique em manipuladores de eventos no divprimeiro será acionado), depois no ul, depois no último no elemento de destino li.

No modelo de bolhas, o contrário acontecerá: o evento será tratado primeiro pelo li, depois pelo ule, finalmente, pelo divelemento.

Para mais informações, veja

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

var logElement = document.getElementById('log');

function log(msg) {
    logElement.innerHTML += ('<p>' + msg + '</p>');
}

function capture() {
    log('capture: ' + this.firstChild.nodeValue.trim());
}

function bubble() {
    log('bubble: ' + this.firstChild.nodeValue.trim());
}

function clearOutput() {
    logElement.innerHTML = "";
}

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);
}
var clearButton = document.getElementById('clear');
clearButton.addEventListener('click', clearOutput);
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;
}
<div>1
    <div>2
        <div>3
            <div>4
                <div>5</div>
            </div>
        </div>
    </div>
</div>
<button id="clear">clear output</button>
<section id="log"></section>

Outro exemplo no JSFiddle .

Arun P Johny
fonte
41
useCaptureagora suportada no IE> = 9. fonte
beatgammit
7
Eu sei que é tarde demais para comentar, mas bom artigo que encontrei aqui catcode.com/domcontent/events/capture.html
Apenas codifique
3
É triclklingo mesmo que capturing? Crockford fala sobre Trickling v. Bubblingesta conversa em vídeo - youtube.com/watch?v=Fv9qT9joc0M&list=PL7664379246A246CB ao redor 1 hr 5 minutes.
Kevin Meredith
1
@KevinMeredith A mesma coisa. "Gotejamento" apenas torna mais fácil lembrar o que os dois modelos não (trickle para baixo , bubble up ).
um gato
7
A resposta acima é correta em relação à ordem na explicação detalhada, mas deixa você pensando que o gotejamento ocorre em segundo lugar com "bolha para cima, gota para baixo". Os eventos sempre passam pela fase de captura antes da fase da bolha. A ordem correta é trickle down=> onElement=>bubble up
expirada
513

Descrição:

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

Captura de eventos

Quando você usa a captura de eventos

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

o manipulador de eventos do elemento1 é acionado primeiro, o manipulador de eventos do elemento2 é acionado por último.

Evento borbulhante

Quando você usa bolhas de eventos

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

o manipulador de eventos do elemento2 é acionado primeiro, o manipulador de eventos do elemento1 é acionado por último.


O que usar?

Depende do que você quer fazer. Não existe melhor. A diferença está na ordem de execução dos manipuladores de eventos. Na maioria das vezes, será bom acionar manipuladores de eventos na fase de bolhas , mas também pode ser necessário acioná-los mais cedo.

Felix Kling
fonte
As duas coisas não acontecem, primeiro capturando e depois borbulhando, e também o que é evento de despacho?
Suraj Jain #
um exemplo gráfico está aqui: javascript.info/bubbling-and-capturing
Ans da comunidade
71

Se houver dois elementos elemento 1 e elemento 2. O elemento 2 está dentro do elemento 1 e anexamos um manipulador de eventos com os dois elementos, digamos onClick. Agora, quando clicarmos no elemento 2, o eventHandler dos dois elementos será executado. Agora, aqui está a pergunta em que ordem o evento será executado. Se o evento anexado com o elemento 1 for executado primeiro, ele será chamado de captura de evento e se o evento anexado com o elemento 2 for executado primeiro, isso será chamado de evento com bolhas. De acordo com o W3C, o evento começará na fase de captura até atingir o objetivo e voltar ao elemento e começar a borbulhar

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

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

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

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 id="div1">
  div 1
  <div id="div2">
    div 2
  </div>
</div>

Por favor, tente alterar true e false.

dinesh_malhotra
fonte
2
@ masterxilo: não há necessidade do Fiddle, o StackOverflow agora suporta código embutido (snippets de pilha) .
Dan Dascalescu 22/10
Em relação the event will start in the capturing phase untill it reaches the target comes back to the element and then it starts bubbling. Eu encontrei apenas o addEventListener com o parâmetro useCaptureque pode ser definido como true ou false; e no HTML 4.0, os ouvintes de eventos foram especificados como atributos de um elemento e useCapture defaults to false. Você poderia vincular a uma especificação que confirma o que você escreveu?
Surfmuggle
25

Eu achei este tutorial em javascript.info muito claro ao explicar este tópico. E o seu resumo de 3 pontos no final está realmente falando dos pontos cruciais. Eu cito aqui:

  1. Os eventos são capturados primeiro até o alvo mais profundo e depois borbulham. No IE <9, eles apenas borbulham.
  2. Todos os manipuladores trabalham no estágio borbulhante excede o addEventListenerúltimo argumento true, que é a única maneira de capturar o evento no estágio de captura.
  3. O borbulhamento / captura pode ser interrompido por event.cancelBubble=true(IE) ou event.stopPropagation() para outros navegadores.
gm2008
fonte
7

Há também a Event.eventPhasepropriedade que pode dizer se o evento está no alvo ou se 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 , esta é a saída usando a eventPhasepropriedade

var logElement = document.getElementById('log');

function log(msg) {
  if (logElement.innerHTML == "<p>No logs</p>")
    logElement.innerHTML = "";
  logElement.innerHTML += ('<p>' + msg + '</p>');
}

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;
}
<div>1
  <div>2
    <div>3
      <div>4
        <div>5</div>
      </div>
    </div>
  </div>
</div>
<button onclick="document.getElementById('log').innerHTML = '<p>No logs</p>';">Clear logs</button>
<section id="log"></section>

Adelin
fonte
5

Bubbling

  Event propagate to the upto root element is **BUBBLING**.

Capturando

  Event propagate from body(root) element to eventTriggered Element is **CAPTURING**.
Kondal
fonte