Saltar al contenido
eventos.js · devschool

Eventos en JavaScript

Lección 28 de 38 · 5 min de lectura · Actualizado el

En esta lección
  1. addEventListener
  2. Eventos más usados
  3. El objeto event
  4. Varios manejadores y quitar manejadores
  5. Eventos de ratón
  6. La propagación de eventos
  7. Delegación de eventos
  8. Un mismo manejador para muchos elementos
  9. Manejadores en el HTML: evítalos
  10. Formularios y preventDefault
  11. Leer lo que escribe el usuario en tiempo real
  12. Junta todo

Un evento es algo que pasa en la página: un clic, una tecla, el envío de un formulario, el scroll… Con JavaScript puedes escuchar esos eventos y ejecutar código cuando ocurren. Es lo que hace que una web sea interactiva.

addEventListener

const boton = document.querySelector("#saludar");

boton.addEventListener("click", () => {
  alert("¡Hola!");
});

Se lee así: “cuando alguien haga click en el botón, ejecuta esta función”. Tiene dos partes:

  1. El tipo de evento, como texto: "click".
  2. La función que se ejecuta cuando ocurre.

También puedes pasar una función con nombre (sin paréntesis, porque no la estás llamando todavía):

function saludar() {
  alert("¡Hola!");
}
boton.addEventListener("click", saludar);

Eventos más usados

EventoCuándo ocurre
clickAl pulsar un elemento
inputCada vez que cambia el texto de un campo
changeAl cambiar un select, checkbox o al salir de un campo
submitAl enviar un formulario
keydownAl pulsar una tecla
mouseenter / mouseleaveAl entrar o salir el ratón de un elemento
DOMContentLoadedCuando el HTML ha terminado de cargar

El objeto event

La función recibe un objeto con información sobre lo que ha pasado:

document.addEventListener("keydown", (evento) => {
  console.log("Has pulsado", evento.key);
});

boton.addEventListener("click", (evento) => {
  console.log(evento.target); // el elemento en el que se hizo clic
});

Varios manejadores y quitar manejadores

Un mismo evento puede tener varios manejadores: basta con llamar varias veces a addEventListener. Se ejecutan en el orden en que se registraron.

Para quitar un manejador, usa removeEventListener con la misma función (por eso necesita tener nombre):

boton.removeEventListener("click", saludar);

Si solo quieres que un manejador se ejecute una vez: boton.addEventListener("click", saludar, { once: true });.

Eventos de ratón

EventoCuándo
click / dblclickClic / doble clic
mouseenter / mouseleaveEl ratón entra / sale del elemento
mouseover / mouseoutEl ratón entra / sale del elemento o de cualquiera de sus hijos
mousemoveEl ratón se mueve encima
mousedown / mouseupSe pulsa / se suelta el botón

La diferencia entre mouseleave y mouseout confunde mucho: si un <div> tiene un párrafo dentro, al pasar el ratón del div al párrafo, mouseout se dispara (has “salido” del div hacia su hijo) y mouseleave no (sigues dentro del div). Normalmente quieres mouseenter y mouseleave.

Hoy la mayoría de dispositivos son táctiles, así que no hagas que nada importante dependa de pasar el ratón por encima: en un móvil no existe. Para interfaces que deben funcionar con ratón, dedo y lápiz a la vez, existen los eventos pointerdown, pointermove y pointerup.

La propagación de eventos

Cuando haces clic en un elemento, el evento no se queda ahí: sube por todos sus antepasados. Si haces clic en una imagen que está dentro de un botón, que está dentro de una tarjeta, que está dentro de un <div>, el clic llega a la imagen, al botón, a la tarjeta y al div. A esto se le llama burbujeo (bubbling).

En cualquiera de ellos puedes saber dónde empezó el evento:

  • evento.target: el elemento donde se hizo clic realmente (la imagen).
  • evento.currentTarget: el elemento que tiene el manejador que se está ejecutando.

Si en algún caso necesitas que el evento no siga subiendo, usa evento.stopPropagation(). Úsalo poco: rompe comportamientos que otros manejadores esperan.

Delegación de eventos

Imagina una lista de 100 tareas, cada una con su botón de borrar. Podrías poner 100 manejadores, uno por botón. Pero gracias a la propagación, basta con uno en el contenedor:

const lista = document.querySelector("#tareas");

lista.addEventListener("click", (evento) => {
  const boton = evento.target.closest(".borrar");
  if (!boton) return;               // el clic no fue en un botón de borrar
  boton.closest("li").remove();     // borra la tarea de ese botón
});

Ventajas:

  • Un solo manejador en lugar de cientos.
  • Funciona también con los elementos que añadas después, sin tener que registrarles nada. Es perfecto para contenido creado dinámicamente.

closest(selector) busca, desde el elemento hacia arriba, el primero que cumple el selector. Es imprescindible aquí, porque evento.target puede ser el icono que hay dentro del botón y no el botón mismo.

Un mismo manejador para muchos elementos

Otra técnica útil: un solo manejador que sabe qué elemento recibió el evento gracias a su id o a sus atributos data-*:

function mostrarFoto(evento) {
  const id = evento.currentTarget.dataset.foto;
  visor.src = `img/${id}.jpg`;
}

for (const miniatura of document.querySelectorAll(".miniatura")) {
  miniatura.addEventListener("click", mostrarFoto);
}

Manejadores en el HTML: evítalos

En código antiguo verás cosas como estas:

<button onclick="saludar()">Hola</button>
<body onload="iniciar()">
boton.onclick = saludar;

Funcionan, pero mezclan HTML y JavaScript, solo permiten un manejador por evento y dan problemas de seguridad. Usa siempre addEventListener.

Formularios y preventDefault

Al enviar un formulario, el navegador recarga la página. Si quieres gestionarlo con JavaScript, tienes que impedirlo:

formulario.addEventListener("submit", (evento) => {
  evento.preventDefault();
  const email = document.querySelector("#email").value;
  console.log("Email:", email);
});

Escucha el submit del formulario, no el click del botón: así también funciona cuando alguien pulsa Enter.

Leer lo que escribe el usuario en tiempo real

const buscador = document.querySelector("#buscar");

buscador.addEventListener("input", () => {
  console.log("Buscando:", buscador.value);
});

.value siempre es un texto. Si esperas un número, conviértelo con Number().

Junta todo

El ejemplo de abajo combina lo que has aprendido: un formulario, el DOM, eventos y funciones. Es una lista de tareas completa en menos de 30 líneas. Modifícala: añade un botón para borrar todas o muestra la fecha de cada tarea.

Pruébalo tú

Cambia el código y pulsa Ejecutar (o Ctrl + Enter).

eventos.html
Resultado

Pon a prueba lo que has aprendido

[JavaScript] ¿Qué ventaja tiene la delegación de eventos?

[JavaScript] En un manejador, ¿qué es evento.target?

¿Te ha quedado claro? Márcala y verás tu progreso en el explorador.