015. DOM: Flujo de Eventos (Burbuja y Captura)

En este capítulo veremos como trabaja Javascript con los eventos. El método addEventListener() dispone de un tercer parámetro que nos permite elegir el tipo de flujo que deseamos (burbuja o captura), y es lo que vamos a trabajar en este capítulo.

El flujo de eventos es la manera mediante la cual se propaga dicho evento. Una vez que un evento se origina, tiene una propagación a lo largo del árbol del DOM, por defecto, dicha propagación se va dando del elemento más interno al mas externo, que es el documento, y esa fase es denominada fase de burbuja, que es el esquema por defecto que los navegadores soportan, de hecho no hay que hacer nada a nuestros manejadores múltiples para que funcione esta fase de burbuja.

Funcionamiento de la fase de captura

En los capítulos anteriores estuvimos asignando eventos de manera individual a cada uno de los botones, pero imaginemos que en una interfaz dinámica, dicha botonera se forma a partir de un catálogo que tengamos en una base de datos, por lo que tenemos que ir a consultar la base de datos, imprimir un botón por cada registro que venga de la base de datos, y a ese botón asignarle dinámicamente un evento, para lo que tendríamos que asignar dinamicamente el evento a todos los elementos.

Veamos un ejm para entender todo de mejor manera.

Ejm

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Flujo de eventos</title>
<style>
.eventos-flujo div {
padding: 4rem;
font-size: 2rem;
text-align: center;
}

.uno {
background-color: yellow;
}

.dos {
background-color: gold;
}

.tres {
background-color: lightyellow;
}
</style>
</head>
<body>
<h1>Flujo de eventos</h1>
<section class="eventos-flujo">
 <div class="uno">
  1
  <div class="dos">
   2
   <div class="tres">
     3
   </div>
 </div>
</div>
</section>

<script>
const $divEventos = document.querySelectorAll(".eventos-flujo div");
console.log($divEventos);
// Devuelve un nodeList

// Vamos a crear previamente la función flujoEventos
// de donde va a tirar nuestro bucle forEach
function flujoEventos(e) {
console.log("Hola")
}

$divEventos.forEach(div => {
div.addEventListener("click", flujoEventos);
});
</script>
</body>
</html>

Cuando hago clic al div3, internamente la div3 está dentro de la div2 y de la div1, y como los 3 elementos tienen asignado ese evento clic, ahí vemos la propagación, la div3 imprimirá en consola 3 veces Hola, la div2 lo hará dos veces, y la div1 lo hará únicamente una vez.

Vamos a cambiar la función flujoEventos() con la siguiente sintaxis.

function flujoEventos(e) {
  console.log(`Hola, te saluda ${this.className}, el clic
lo originó ${e.target.className}`)
}

A esto se le denomina la fase de burbuja, porque va del elemento más interno, que tiene asociado el evento, hacia el más externo.

La función addEventListener() tiene un tercer parámetro opcional, que son una serie de opciones:

  • false: estamos en fase de burbuja, por lo tanto, el flujo de los eventos se propaga desde el más interno hasta el más externo dentro del árbol del DOM.
  • true: origina la fase de captura, la cual va de los eventos más externos hasta el elemento más interno.

Fase de burbuja

La sintaxis de nuestra función manejadora addEventListener()  sería la siguiente.

div.addEventListener("click", flujoEventos);
// O bien
div.addEventListener("click", flujoEventos, false);

Fase de captura

div.addEventListener("click", flujoEventos, true);

En la práctica, normalmente no se utiliza este tercer parámetro de la función addEventListener(). En foros de diseño web se comenta que cuando la estructura del DOM tiene muchos elementos, existen comprobaciones matemáticas las cuales dicen que en este tipo de elementos concatenados donde tenemos el mismo evento asociado a elemento padre, hijo, nieto… es decir, que se tenga que propagar el evento, funciona mejor la fase de captura que la de burbuja, es más óptima, ya que no consume tanta memoria.

Tanto fase de captura como de burbuja la podemos omitir si delegamos los eventos a un elemento padre mas externo, lo que ayudará a mejorar el rendimiento de la memoria y los recursos que nuestra aplicación ocupe en el navegador.

Adicionales

Sobre el tercer parámetro, además de tener true o false, tenemos otras palabras reservadas.

  • Podemos pasar un objeto al que le podemos pasar las siguientes propiedades
    • capture: esta propiedad hace referencia a si la fase es de burbuja o de captura, dependiendo de si el valor que asignamos a esta propiedad es false o true.
    • once: si lo activamos a true, nuestro evento se va a ejecutar una sóla vez, si lo activamos a false se ejecutará siempre

La sintaxis de nuestro addEventListener() sería la siguiente:

div.addEventListener("click", flujoEventos, {
capture: (true / false),
once: (true / false),
});
Scroll al inicio