¿Qué es el evento burbujeante y capturador?

Respuestas:

1441

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 .

Ejemplo

<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 divprimero (haga clic en los controladores de eventos en el divdisparará 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 uly 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>

Otro ejemplo en JSFiddle .

Arun P Johny
fuente
41
useCaptureahora compatible con IE> = 9. fuente
beatgammit
77
Sé que es demasiado tarde para poner un comentario, pero un buen artículo que encontré aquí catcode.com/domcontent/events/capture.html
solo codifique el
3
Es triclklinglo mismo que capturing? Conversaciones sobre Crockford Trickling v. Bubblingen esta charla de vídeo - youtube.com/watch?v=Fv9qT9joc0M&list=PL7664379246A246CB alrededor 1 hr 5 minutes.
Kevin Meredith
1
@KevinMeredith Lo mismo. "Goteo" sólo hace que sea más fácil de recordar lo que los dos modelos no (goteo hacia abajo , la burbuja arriba ).
un gato
77
La respuesta anterior es correcta con respecto al orden en la explicación detallada, pero te deja pensando que el goteo ocurre en segundo lugar con "burbuja arriba, goteo abajo". Los eventos siempre pasan por la fase de captura antes de la fase de burbuja. El orden correcto es trickle down=> onElement=>bubble up
ejecuta el
513

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.

Felix Kling
fuente
No sucede ambas cosas, primero capturando y luego burbujeando, ¿qué es el evento de despacho?
Suraj Jain el
un ejemplo gráfico está aquí: javascript.info/bubbling-and-capturing
Community Ans
71

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.

dinesh_malhotra
fuente
2
@masterxilo: no necesita Fiddle, StackOverflow ahora admite código en línea (fragmentos de pila) .
Dan Dascalescu
En cuanto a 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 useCaptureque 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ó?
surfmuggle
25

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í:

  1. Los eventos primero se capturan hasta el objetivo más profundo, luego se disparan. En IE <9 solo burbujean.
  2. Todos los controladores funcionan en la etapa de burbujeo, excepto addEventListenercon el último argumentotrue , que es la única forma de detectar el evento en la etapa de captura.
  3. El burbujeo / captura puede ser detenido por event.cancelBubble=true(IE) o event.stopPropagation() por otros navegadores.
gm2008
fuente
7

También existe la Event.eventPhasepropiedad 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 eventPhasepropiedad

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
fuente
5

Burbujeante

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

Capturar

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