this vs event.target

  • Formato: lectura
  • Duración: 10min

Cuando empezamos a tener aplicaciones con mucho Javascript pueden empezar a surgir pequeños problemas de optimización, como que la aplicación tarde en responder o que tenga un consumo excesivo de memoria. Uno de esos problemas puede estar en los eventos asignados al DOM. Supongamos que tenemos una lista bastante grande de elementos. Al hacer click en cada uno de esos elementos se ejecutará una función que muestra la información del item elegido. El código que implementemos recogerá todos los elementos de la lista, la recorre mediante un bucle y asigna a cada elemento un evento. Es ahí donde podemos tener problemas. A cada elemento se le está asignando un evento, que a su vez está recibiendo una función anónima. Esto quiere decir que si tenemos una lista de 1000 elementos, estaremos asignando 1000 eventos, incrementando el uso de RAM de nuestra aplicación.

Para optimizar esto podemos hacer un solo evento sobre la lista completa, y cuando se haga click comprobar el elemento que se ha pulsado. Podemos obtener ese elemento con event.target.

Ya saben que cuando queremos escuchar eventos en JavaScript (por ejemplo, cuando se hace click en un botón), la sintaxis es la siguiente.

//vaniila
el.addEventListener('eventType', () =>
  // eventHandler
);
// jQuery
$('elSelector').on('eventType', () =>
  // eventHandler
);

Donde eventType es un tipo de evento (o puedes encontrar en la documentación de JS) y el eventHandler es la función que se ejecutará cuando el eventType se dispare.

Hasta ahi, perfecto. Sin embargo, si quieres que varios elementos escuchen el mismo eventType y ejecuten el mismo eventHandler (por ejemplo, en una galería de fotos poder hacer clic en cualquiera de las miniaturas para mostrar la versión ampliada), nuestro primer razonamiento sería iterar sobre ellos.

var galleryImg = document.querySelectorAll('.gallery-item');
for(let i = 0; i < galleryImg.length; i++) {
  galleryImg[i].addEventListener('eventType', () =>
    // eventHandler
  )
}

Si usamos jQuery, es más sencillo aún, pues hace la iteración por nosotros

$('.gallery-item').on('eventType', () =>
  // eventHandler
)

Sin embargo, el principal problema con estos enfoques es que solo aplica a los elementos existentes en el DOM al cargar la página. Con lo cual, si añadimos elementos dinámicamente, estos no se verán afectados por el evento. Por otro lado, si evitamos la iteración, podemos ganar rendimiento. Para eso utilizamos la Delegación de eventos que consiste en escuchar el evento en el elemento padre solamente para luego capturarlo cuando ocurra en sus hijos. Esto gracias a un comportamiento de los eventos que vimos en la lectura pasada Bubbling.

Recordemos Bubbling

Bubbling (burbujeo) es una fase de los eventos (la otra es capturing y ambos dan para un próximo post en más detalle) que significa que cuando un evento ocurre en el DOM, es capturado en el elemento HTML más profundo posible, y de ahí se va elevando hacia sus padres en orden de jerarquía hasta llegar al objeto global (window). Por lo tanto, cuando un evento ocurre en un elemento, también está ocurriendo en sus padres.

Delegación de eventos

Ahora que sabemos que si un evento ocurre en un hijo, también está ocurriendo en sus padres. Volvamos al ejemplo de la galería. Ahora no necesitamos iterar sobre los elementos, sino escuchar el evento en el padre.

Tomemos en cuenta el siguiente HTML

<div class="gallery-container">
  <a href="" class="gallery-item"><img src="" alt=""></a>
  <a href="" class="gallery-item"><img src="" alt=""></a>
  <a href="" class="gallery-item"><img src="" alt=""></a>
  <a href="" class="gallery-item"><img src="" alt=""></a>
  <a href="" class="gallery-item"><img src="" alt=""></a>
  <a href="" class="gallery-item"><img src="" alt=""></a>
  <a href="" class="gallery-item"><img src="" alt=""></a>
  <a href="" class="gallery-item"><img src="" alt=""></a>
  <a href="" class="gallery-item"><img src="" alt=""></a>
</div>

Tenemos nueve elementos gallery-item. Pero podrían ser más. Sin embargo, como ya conocemos la delegación, escucharemos el evento una sola vez en el padre. Recuerda que podemos pasar el objeto Event como parámetro (lo nombraremos e en nuestros ejemplos), al eventHandler para así obtener el target que es el elemento que dispara el evento.

let gallery = document.querySelector('.gallery-item');
gallery.addEventListener('eventType', e =>
  console.log(e.target) // nos imprime en consola el elemento que dispara el
  evento
);

Y como en nuestro caso queremos capturar el evento en todos los elementos con la clase gallery-item, lo haremos así:

// vanilla
let gallery = document.querySelector('gallery-container');
gallery.addEventListener('eventType', e => {
  if(e.target.classList.contains('gallery-item')){
    //...
  }
});
// jQuery
$('.gallery-container').on('eventType', '.gallery-item', () =>
  //...
);

Sobre ES6 y this

En esta lectura estamos usando ES6 (si no lo estás usando, deberías). Ten en cuenta que si usas una arrow function para el eventHandler no podrás capturar el elemento que dispara el evento usando this (como en ES5) por eso se recomienda usar e.target


Continuar

results matching ""

    No results matching ""