Eventos en JavaScript
Los eventos permiten que tu página reaccione a acciones del usuario: clics, teclas, movimiento del mouse, envío de formularios y mucho más. Son la base de toda interfaz interactiva.
¿Qué es un evento?
Un evento es algo que ocurre en la página — el usuario hace clic, mueve el mouse, escribe en un input, o la página termina de cargar. JavaScript puede "escuchar" esos eventos y ejecutar una función cuando ocurran.
// La forma correcta: addEventListener
const boton = document.getElementById("mi-btn");
boton.addEventListener("click", function() {
alert("¡Hiciste clic!");
});
// Con arrow function — más común
boton.addEventListener("click", () => {
document.getElementById("resultado").textContent = "¡Clic recibido!";
});
<button onclick="hacer()"> y boton.onclick = fn funcionan, pero tienen limitaciones: solo podés asignar una función y mezclan HTML con JS. addEventListener es siempre la mejor opción.
Tipos de eventos más usados
Mouse
el.addEventListener("click", fn); // clic izquierdo
el.addEventListener("dblclick", fn); // doble clic
el.addEventListener("mouseenter", fn); // el mouse entra al elemento
el.addEventListener("mouseleave", fn); // el mouse sale del elemento
el.addEventListener("mousemove", fn); // el mouse se mueve dentro
el.addEventListener("contextmenu",fn); // clic derecho
Teclado
document.addEventListener("keydown", (e) => {
console.log(e.key); // "Enter", "a", "ArrowUp", etc.
console.log(e.code); // "KeyA", "Enter", "Space"
console.log(e.ctrlKey); // true si Ctrl estaba apretado
console.log(e.shiftKey); // true si Shift estaba apretado
if (e.key === "Enter") { /* procesar */ }
if (e.ctrlKey && e.key === "s") {
e.preventDefault(); // evita que el navegador guarde la página
guardar();
}
});
document.addEventListener("keyup", fn); // al soltar la tecla
document.addEventListener("keypress", fn); // deprecado — usá keydown
Formularios
// Input — se dispara en cada cambio de carácter
input.addEventListener("input", fn);
// Change — se dispara al perder el foco con un valor diferente
input.addEventListener("change", fn);
// Focus y blur
input.addEventListener("focus", fn); // al entrar en el campo
input.addEventListener("blur", fn); // al salir del campo
// Formulario
form.addEventListener("submit", (e) => {
e.preventDefault(); // evita que la página se recargue
// procesar datos...
});
Probá el Ejemplo 2: Eventos de formulario
El objeto event
Cuando ocurre un evento, JavaScript pasa automáticamente un objeto event
a la función manejadora. Contiene información sobre lo que pasó.
document.addEventListener("click", (event) => {
// Información del evento
event.type; // "click"
event.target; // el elemento que recibió el clic
event.currentTarget; // el elemento donde está el listener
// Posición del mouse
event.clientX; // posición X relativa a la ventana
event.clientY; // posición Y relativa a la ventana
event.pageX; // posición X relativa al documento
// Control del evento
event.preventDefault(); // cancela el comportamiento por defecto
event.stopPropagation(); // detiene la propagación hacia arriba
});
// Ejemplo práctico — saber en qué elemento se hizo clic
document.addEventListener("click", (e) => {
console.log("Elemento:", e.target.tagName);
console.log("ID:", e.target.id);
console.log("Clases:", e.target.className);
});
Delegación de eventos
En vez de poner un listener en cada elemento hijo, ponés uno solo en el padre
y usás event.target para saber cuál fue el origen. Es más eficiente
y funciona incluso con elementos creados dinámicamente.
// Sin delegación — un listener por cada botón (ineficiente)
document.querySelectorAll(".btn-borrar").forEach(btn => {
btn.addEventListener("click", () => btn.parentElement.remove());
});
// Con delegación — un solo listener en el padre (eficiente)
document.getElementById("lista").addEventListener("click", (e) => {
// e.target es el elemento que recibió el clic
if (e.target.classList.contains("btn-borrar")) {
e.target.closest("li").remove();
}
if (e.target.classList.contains("btn-completar")) {
e.target.closest("li").classList.toggle("completada");
}
});
e.target.closest("li") sube por los ancestros del elemento y devuelve el primer <li> que encuentre. Es ideal para encontrar el contenedor cuando el clic ocurre en un hijo.
Remover listeners y una sola vez
// Guardar referencia a la función para poder removerla después
function manejarClic() {
console.log("clic");
}
boton.addEventListener("click", manejarClic);
// ... más tarde:
boton.removeEventListener("click", manejarClic);
// Ejecutar el listener una sola vez con { once: true }
boton.addEventListener("click", () => {
console.log("Solo se ejecuta la primera vez");
}, { once: true });
// AbortController — remover múltiples listeners a la vez
const controller = new AbortController();
const signal = controller.signal;
boton.addEventListener("click", fn1, { signal });
input.addEventListener("input", fn2, { signal });
form.addEventListener("submit", fn3, { signal });
// Remover todos de una vez
controller.abort();
Ejemplo Completo — Calculadora interactiva
Una calculadora que combina eventos de clic, teclado y formulario:
const inputA = document.getElementById("numA");
const inputB = document.getElementById("numB");
const resultado = document.getElementById("resultado");
function calcular(operacion) {
const a = parseFloat(inputA.value) || 0;
const b = parseFloat(inputB.value) || 0;
const ops = {
suma: a + b,
resta: a - b,
mult: a * b,
div: b !== 0 ? a / b : "Error: división por cero",
};
const res = ops[operacion] ?? "Operación inválida";
resultado.textContent = typeof res === "number"
? res.toFixed(4).replace(/\.?0+$/, "")
: res;
}
// Clic en cada botón de operación
document.querySelectorAll("[data-op]").forEach(btn => {
btn.addEventListener("click", () => calcular(btn.dataset.op));
});
// Teclado — shortcuts
document.addEventListener("keydown", (e) => {
if (e.key === "+") calcular("suma");
if (e.key === "-") calcular("resta");
if (e.key === "*") calcular("mult");
if (e.key === "/") { e.preventDefault(); calcular("div"); }
});
Probá el Ejemplo 4: Calculadora interactiva
Buenas Prácticas
- Siempre addEventListener: evitá
onclicken HTML y como propiedad - preventDefault() en formularios: siempre que procesés el submit con JS, evitá el recargado de página
- Delegación para listas dinámicas: si agregás elementos al DOM después de cargar, el listener en el padre los captura automáticamente
- { once: true } para eventos únicos: más limpio que remover manualmente el listener
- Guardá referencias si vas a remover:
removeEventListenernecesita la misma referencia de función — las arrow functions anónimas no se pueden remover - No abuses de listeners en document: ponerlos en el elemento más específico posible es más eficiente