Eventos y formularios
💡 🎯 Al terminar esta lección podrás…
- Reaccionar a clics, teclas y formularios con
addEventListener. - Leer los campos de un formulario y validarlos con mensajes accesibles.
- Usar
preventDefaulty entender el burbujeo. - Aplicar la delegación de eventos en listas dinámicas.
1.Qué es un evento
Un evento es algo que ocurre en la página: un clic, una tecla pulsada, un formulario enviado, la ventana que cambia de tamaño, una imagen que termina de cargar. JavaScript te permite escuchar esos eventos y ejecutar una función cuando suceden. Así la página deja de ser un documento estático y se vuelve interactiva.
elemento.addEventListener("tipo-de-evento", funcion);
// ① qué escuchar ② qué hacer
La función que pasas se llama manejador (*handler*) o callback. No se ejecuta al escribirla: el navegador la guarda y la llama cada vez que ocurre el evento.
⚠️ Importante · No pongas paréntesis
boton.addEventListener("click", saludar) pasa la función para que el navegador la llame cuando toque. boton.addEventListener("click", saludar()) la ejecuta ya y pasa su resultado. Es el error más común con eventos.
2.Los eventos más usados
| Evento | Cuándo ocurre | Típico en |
|---|---|---|
click | Se pulsa (con ratón, dedo o teclado en un botón) | Botones, enlaces, tarjetas |
dblclick | Doble clic | |
input | Cada vez que cambia lo escrito | Buscadores en vivo, contadores de caracteres |
change | Cuando el valor cambia y se confirma (al salir del campo) | select, checkbox, radio |
submit | Se envía un <form> | Formularios |
keydown / keyup | Se pulsa / suelta una tecla | Atajos, juegos |
mouseover / mouseout | El cursor entra / sale | Efectos |
focus / blur | El elemento recibe / pierde el foco | Validar al salir del campo |
scroll, resize | Se desplaza / cambia el tamaño | Barras, cabeceras |
DOMContentLoaded | El HTML ya se leyó | Iniciar el programa |
load | Todo cargó (imágenes incluidas) |
3.El objeto del evento
El navegador llama a tu función pasándole un objeto con información sobre lo ocurrido. Por convención se llama evento o e:
| Propiedad | Qué da |
|---|---|
e.target | El elemento donde ocurrió el evento |
e.currentTarget | El elemento al que está pegado el manejador |
e.type | El nombre del evento ("click") |
e.key | La tecla pulsada ("Enter", "a", "Escape") |
e.clientX, e.clientY | Posición del cursor |
e.preventDefault() | Cancela la acción por defecto |
e.stopPropagation() | Detiene que el evento «suba» a los padres |
4.Formularios: submit y preventDefault
Un formulario HTML, al enviarse, recarga la página y manda los datos al servidor. Con JavaScript casi siempre queremos evitarlo y procesar los datos nosotros. Para eso, e.preventDefault():
💡 Consejo · Escucha submit, no click
Escucha submit en el <form>, no click en el botón. Así también funciona al pulsar Enter dentro de un campo, y respetas la validación del navegador (required, type="email"…).
Leer los valores de los campos
| Campo | Propiedad | Tipo de dato |
|---|---|---|
input type="text", textarea, select | .value | Siempre texto (convierte con Number()) |
input type="number" | .value / .valueAsNumber | Texto / número |
input type="checkbox" | .checked | true / false |
input type="radio" (grupo) | querySelector("input[name=x]:checked")?.value | Texto o undefined |
| Todo el formulario | Object.fromEntries(new FormData(form)) | Un objeto con todos los campos |
5.Validar y mostrar mensajes
HTML ya valida mucho (required, minlength, type="email", pattern). JavaScript te permite reglas propias y mensajes claros dentro de la página, en lugar de ventanas emergentes:
- Pon el mensaje junto al campo y enlázalo con
aria-describedby; usarole="alert"para que se anuncie. - Marca el campo con
aria-invalid="true"y devuelve el foco al primer campo con error. - El mensaje debe decir qué pasó y cómo arreglarlo.
form.checkValidity()ycampo.validityconsultan la validación nativa.
6.Propagación y delegación de eventos
Cuando ocurre un evento en un elemento, «sube» por sus ancestros: primero se avisa al elemento, luego a su padre, a su abuelo… hasta document. A esto se le llama burbujeo (*bubbling*).
Y de ahí sale una técnica muy potente, la delegación de eventos: en lugar de poner un manejador a cada elemento de una lista, pones uno solo en el contenedor y miras e.target para saber cuál se pulsó. Funciona también con los elementos que añadas después.
📌 Nota · closest()
e.target.closest("li") sube desde el elemento pulsado hasta encontrar el li más cercano. Es más robusto que e.target a secas, porque el clic puede caer en un <strong> dentro del <li>.
7.Teclado y accesibilidad
- Usa
<button>para las acciones: funciona con ratón, teclado (Enter, Espacio) y lector de pantalla, sin hacer nada. - No pongas
clicken un<div>o<span>: nadie podrá usarlo con teclado. - Para atajos, escucha
keydowny compruebae.key(por ejemplo"Escape"para cerrar). - Nunca dependas solo del ratón (
mouseover): ofrece tambiénfocus. - Si cambias algo en la página, avísalo con una región
aria-liveorole="status".
8.Más opciones de addEventListener
| Opción | Efecto | Ejemplo |
|---|---|---|
{ once: true } | El manejador se ejecuta una sola vez | boton.addEventListener("click", f, { once: true }) |
removeEventListener | Quita un manejador (necesita la misma función) | boton.removeEventListener("click", f) |
{ passive: true } | Promete no cancelar (mejora el rendimiento del scroll) | addEventListener("scroll", f, { passive: true }) |
function saludar() { console.log("¡Hola!"); }
boton.addEventListener("click", saludar);
boton.removeEventListener("click", saludar); // funciona porque es la misma función
// Con una flecha anónima NO se puede quitar:
boton.addEventListener("click", () => console.log("x"));
💡 Consejo · Debounce
Para eventos que se disparan muchísimas veces (input, scroll, resize), conviene esperar a que el usuario pare antes de hacer algo costoso. Esa técnica se llama *debounce* y se apoya en setTimeout, que verás en la siguiente lección.
9.Errores frecuentes
addEventListener("click", funcion())con paréntesis: se ejecuta de inmediato.- Olvidar
e.preventDefault()en unsubmit: la página se recarga y «desaparece» todo. - Escuchar
clicken el botón del formulario en lugar desubmiten el formulario. - Leer
.valuecomo si fuera número: es texto."2" + "3"es"23". - Añadir un manejador por cada elemento de una lista en vez de usar delegación.
- Esperar que un manejador funcione sobre elementos que aún no existen (usa delegación).
- Eventos en
divsin teclado: inaccesible. Usabutton. - Manejadores dentro de bucles que acaban duplicados al repintar: se ejecutan varias veces.
- Atributos como
onclick="…"en el HTML: difíciles de mantener.
📒 Apuntes para llevar
elemento.addEventListener("evento", funcion)ejecuta tu función cuando ocurre el evento; pasa la función, no la llames.- Eventos habituales:
click,input,change,submit,keydown,focus,DOMContentLoaded. - El objeto del evento (
e) datarget,key,type… ypreventDefault()cancela la acción por defecto. - En un formulario escucha
submity llama ae.preventDefault(); lee los campos con.value,.checkedoFormData. - Los valores de los campos son texto: conviértelos con
Number(). - Valida con mensajes dentro de la página, enlazados con
aria-describedbyy anunciados conrole="alert". - Los eventos burbujean: la delegación pone un solo manejador en el contenedor y usa
e.target.closest(…). - Usa
buttonpara acciones, soporta el teclado y evitaonclicken el HTML.
10.Glosario
| Término | Significado |
|---|---|
| Evento | Algo que ocurre en la página (clic, tecla, envío…). |
| Manejador (handler) | Función que se ejecuta cuando ocurre un evento. |
addEventListener | Método que registra un manejador para un evento. |
| Objeto del evento | Información que recibe el manejador (e). |
preventDefault() | Cancela el comportamiento por defecto del navegador. |
| Burbujeo (bubbling) | Propagación del evento desde el elemento hacia sus ancestros. |
| Delegación | Un manejador en el padre que atiende a los hijos usando e.target. |
FormData | Objeto que reúne los valores de un formulario. |
🧠 Comprueba lo aprendido
Elige una respuesta en cada pregunta. Verás al instante si acertaste y por qué.
¿Cuál es la forma correcta de asociar una función a un clic?
Se pasa la función sin paréntesis; el navegador la llamará.
Un formulario recarga la página al enviarse. ¿Cómo evitarlo?
preventDefault cancela el envío por defecto.
input.value de un input type="number" con «5» es…
Los valores de los campos siempre son texto.
¿Para qué sirve la delegación de eventos?
El evento sube hasta el contenedor, que decide qué hijo fue.
¿Por qué es mejor un <button> que un <div> con click?
Un div no recibe foco ni se activa con Enter ni Espacio.
Tu progreso se guarda en este navegador y se refleja en el índice del curso.
💡 🚀 ¡Ahora te toca!
La práctica fija lo aprendido. Pasa al ejercicio de esta lección.