O que é o evento borbulhando e capturando?
5 answers
Borbulhar e capturar eventos são duas formas de propagação de eventos na API DOM HTML, quando um evento ocorre em um elemento dentro de outro elemento, e ambos os elementos registraram uma pega para esse evento. O modo de propagação do evento determina em qual ordem os elementos recebem o evento .
Com borbulhar, o evento é primeiro capturado e tratado pelo elemento mais interior e depois propagado para elementos exteriores. Com a captura, o evento é o primeiro capturada pelo elemento mais externo e propagada aos elementos interiores. A captura também é chamada de "trickling", o que ajuda a lembrar a ordem de propagação:Para baixo, para cima.
Nos velhos tempos, o Netscape defendia a captura de eventos, enquanto a Microsoft promovia a borbulhagem de eventos. Ambos fazem parte da norma W3C Document Object Model Events (2000).
IE apenas o borbulhante de eventos , enquanto que IE9+ e todos os principais navegadores suportam ambos. Por outro lado, o desempenho da borbulhagem de eventos Pode ser ligeiramente inferior para Dom complexos.
Podemos usar o addEventListener(type, listener, useCapture)
para registar os manipuladores de eventos tanto no modo borbulhante (por omissão) como no modo de captura. Para usar o modelo de captura passar o terceiro argumento como true
.
Exemplo
<div>
<ul>
<li></li>
</ul>
</div>
Na estrutura acima, assuma que ocorreu um evento click no elemento li
.
Ao capturar o modelo, o evento será tratado pelo div
Primeiro (clique em manipuladores de eventos no div
irá disparar primeiro), depois no ul
, depois no último no elemento alvo, li
.
No modelo borbulhante, o oposto acontecerá: o evento será primeiro tratado pelo li
, depois pelo ul
, e finalmente pelo elemento div
.
Para mais informações, ver
- ordem de eventos em QuirksMode
- addEventListener em MDN
- Os eventos avançaram em QuirksMode
No exemplo abaixo, se você clicar em qualquer um dos elementos destacados, você pode ver que a fase de captura do fluxo de propagação do evento ocorre primeiro, seguido pela fase borbulhante.
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());
}
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>
<section id="log"></section>
Designação das mercadorias:
quirksmode.org tem uma boa descrição disto. Em poucas palavras (copiado de quirksmode):
Captura de Eventos
Quando usar a captura de Eventos
| | ---------------| |----------------- | element1 | | | | -----------| |----------- | | |element2 \ / | | | ------------------------- | | Event CAPTURING | -----------------------------------
O responsável pelo evento do element1 dispara primeiro, o responsável pelo evento do element2 dispara em último.
Borbulhar o evento
Quando se usa a borbulhagem de Eventos
/ \ ---------------| |----------------- | element1 | | | | -----------| |----------- | | |element2 | | | | | ------------------------- | | Event BUBBLING | -----------------------------------
O manipulador de eventos do element2 dispara. primeiro, o responsável pelo evento do element1 dispara Por último.
O que usar?
Depende do que queres fazer. Não há melhor. A diferença é a ordem de execução dos responsáveis pelo evento. Na maioria das vezes, não há problema em disparar os manipuladores de eventos na fase bubbling , mas também pode ser necessário despedi-los mais cedo.Se existirem dois elementos, elemento 1 e Elemento 2. O elemento 2 está dentro do elemento 1 e anexamos um manipulador de eventos com ambos os elementos, digamos onClick. Agora, quando clicarmos no elemento 2, então eventHandler para ambos os elementos será executado. Agora aqui a questão é em que ordem o evento será executado. Se o evento associado ao elemento 1 Executar primeiro é chamado captura de eventos e se o evento associado ao elemento 2 Executar primeiro isto é chamado de borbulhamento de eventos. De acordo com W3C o evento começará na fase de captura até atingir o alvo voltar ao elemento e então ele começa a borbulhar
Os estados de captura e borbulhagem são conhecidos pelo parâmetro de Utilização do método addEventListener
Objectivo de Evento.addEventListener (tipo, ouvinte, [, useCapture]);
Por padrão a useCapture é falsa. Significa que está na fase borbulhante.
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>
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. Passo a citar:
Os eventos primeiro são capturados até ao alvo mais profundo,depois sobem. Em Ou seja, Todos os manipuladores trabalham com excepção do estágio borbulhante. addEventListener com o último argumento verdadeiro, que é a única maneira de apanhe o evento ao capturar o palco.
- borbulhar / capturar pode ser parou por evento.cancelBubble=true (IE) ou event.stopPropagation () para outros navegadores.
Event.eventPhase
propriedade que pode dizer-lhe se o evento está no alvo ou vem de outro lugar.
Note que a compatibilidade do navegador ainda não foi determinada. Testei-o em cromo (66.0.3359.181) e Firefox (59.0.3) e é suportado lá.
Expandindo-se no já grande trecho da resposta aceite , Este é o resultado usando a propriedade eventPhase
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>