Qual é a diferença entre bubbling de evento e captura? Quando se deve usar borbulhar vs capturar?
Qual é a diferença entre bubbling de evento e captura? Quando se deve usar borbulhar vs capturar?
Respostas:
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
.
<div>
<ul>
<li></li>
</ul>
</div>
Na estrutura acima, assuma que ocorreu um evento de clique no li
elemento
No modelo de captura, o evento será tratado pelo div
primeiro (clique em manipuladores de eventos no div
primeiro 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 ul
e, finalmente, pelo div
elemento.
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>
useCapture
agora suportada no IE> = 9. fonte
triclkling
o mesmo que capturing
? Crockford fala sobre Trickling v. Bubbling
esta conversa em vídeo - youtube.com/watch?v=Fv9qT9joc0M&list=PL7664379246A246CB ao redor 1 hr 5 minutes
.
trickle down
=> onElement
=>bubble up
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.
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.
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 useCapture
que 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?
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:
- Os eventos são capturados primeiro até o alvo mais profundo e depois borbulham. No IE <9, eles apenas borbulham.
- Todos os manipuladores trabalham no estágio borbulhante excede o
addEventListener
último argumentotrue
, que é a única maneira de capturar o evento no estágio de captura.- O borbulhamento / captura pode ser interrompido por
event.cancelBubble=true
(IE) ouevent.stopPropagation()
para outros navegadores.
Há também a Event.eventPhase
propriedade 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 eventPhase
propriedade
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>