¿Cuál es la diferencia entre burbujear y capturar eventos? ¿Cuándo se debe usar burbujear frente a capturar?
¿Cuál es la diferencia entre burbujear y capturar eventos? ¿Cuándo se debe usar burbujear frente a capturar?
Respuestas:
El burbujeo y la captura de eventos son dos formas de propagación de eventos en la API DOM de HTML, cuando ocurre un evento en un elemento dentro de otro elemento, y ambos elementos han registrado un identificador para ese evento. El modo de propagación de eventos determina en qué orden los elementos reciben el evento .
Con el burbujeo, el elemento primero captura y maneja el evento y luego lo propaga a los elementos externos.
Con la captura, el evento es capturado primero por el elemento más externo y propagado a los elementos internos.
La captura también se llama "goteo", lo que ayuda a recordar el orden de propagación:
gotear, burbujear
En los viejos tiempos, Netscape abogó por la captura de eventos, mientras que Microsoft promovió el burbujeo de eventos. Ambos son parte del estándar de eventos del modelo de objetos de documento del W3C (2000).
IE <9 solo usa burbujeo de eventos , mientras que IE9 + y todos los principales navegadores admiten ambos. Por otro lado, el rendimiento del burbujeo de eventos puede ser ligeramente inferior. para los DOM complejos.
Podemos usar el addEventListener(type, listener, useCapture)
para registrar controladores de eventos en modo burbujeante (predeterminado) o de captura. Para usar el modelo de captura, pase el tercer argumento comotrue
.
<div>
<ul>
<li></li>
</ul>
</div>
En la estructura anterior, suponga que se produjo un evento de clic en el li
elemento.
En el modelo de captura, el evento será manejado por el div
primero (haga clic en los controladores de eventos en el div
disparará primero), luego en el ul
, luego al último en el elemento de destino,li
.
En el modelo burbujeante, sucederá lo contrario: el evento será manejado primero por el elemento li
, luego por el elemento ul
y finalmente div
.
Para más información, ver
En el siguiente ejemplo, si hace clic en cualquiera de los elementos resaltados, puede ver que la fase de captura del flujo de propagación del evento ocurre primero, seguida de la fase de burbujeo.
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
ahora compatible con IE> = 9. fuente
triclkling
lo mismo que capturing
? Conversaciones sobre Crockford Trickling v. Bubbling
en esta charla de vídeo - youtube.com/watch?v=Fv9qT9joc0M&list=PL7664379246A246CB alrededor 1 hr 5 minutes
.
trickle down
=> onElement
=>bubble up
Descripción:
quirksmode.org tiene una buena descripción de esto. En pocas palabras (copiado de quirksmode):
Captura de eventos
Cuando usa la captura de eventos
| | ---------------| |----------------- | element1 | | | | -----------| |----------- | | |element2 \ / | | | ------------------------- | | Event CAPTURING | -----------------------------------
el controlador de eventos de element1 se dispara primero, el controlador de eventos de element2 se dispara por último.
Evento burbujeante
Cuando usa burbujeo de eventos
/ \ ---------------| |----------------- | element1 | | | | -----------| |----------- | | |element2 | | | | | ------------------------- | | Event BUBBLING | -----------------------------------
el controlador de eventos de element2 se dispara primero, el controlador de eventos de element1 se dispara por último.
¿Qué usar?
Depende de lo que quieras hacer. No hay mejor La diferencia es el orden de ejecución de los controladores de eventos. La mayoría de las veces estará bien disparar controladores de eventos en la fase de burbujeo , pero también puede ser necesario dispararlos antes.
Si hay dos elementos, elemento 1 y elemento 2. El elemento 2 está dentro del elemento 1 y adjuntamos un controlador de eventos con ambos elementos, digamos onClick. Ahora, cuando hacemos clic en el elemento 2, se ejecutará eventHandler para ambos elementos. Ahora aquí la pregunta es en qué orden se ejecutará el evento. Si el evento adjunto con el elemento 1 se ejecuta primero, se llama captura de eventos y si el evento adjunto con el elemento 2 se ejecuta primero, esto se llama burbujeo de eventos. Según el W3C, el evento comenzará en la fase de captura hasta que alcance el objetivo, regrese al elemento y luego comience a burbujear
Los estados de captura y burbujeo son conocidos por el parámetro useCapture del método addEventListener
eventTarget.addEventListener (type, listener, [, useCapture]);
Por defecto useCapture es falso. Significa que está en la fase de burbujeo.
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, intente cambiar verdadero y falso.
the event will start in the capturing phase untill it reaches the target comes back to the element and then it starts bubbling
. Solo encontré que addEventListener tiene el parámetro useCapture
que se puede establecer en verdadero o falso; y en HTML 4.0, los detectores de eventos se especificaron como atributos de un elemento y useCapture defaults to false
. ¿Podría vincular a una especificación que confirme lo que escribió?
He encontrado este tutorial en javascript.info para ser muy claro al explicar este tema. Y su resumen de 3 puntos al final realmente está hablando de los puntos cruciales. Lo cito aquí:
- Los eventos primero se capturan hasta el objetivo más profundo, luego se disparan. En IE <9 solo burbujean.
- Todos los controladores funcionan en la etapa de burbujeo, excepto
addEventListener
con el último argumentotrue
, que es la única forma de detectar el evento en la etapa de captura.- El burbujeo / captura puede ser detenido por
event.cancelBubble=true
(IE) oevent.stopPropagation()
por otros navegadores.
También existe la Event.eventPhase
propiedad que puede decirle si el evento está en el destino o si proviene de otro lugar.
Tenga en cuenta que la compatibilidad del navegador aún no está determinada. Lo probé en Chrome (66.0.3359.181) y Firefox (59.0.3) y es compatible allí.
Ampliando el fragmento ya excelente de la respuesta aceptada , esta es la salida que usa la eventPhase
propiedad
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>