Eventos del DOM
Los eventos se disparan para avisar al código de "cambios de interés" que pueden afectar a su ejecución. Estos pueden originarse por interacciones del usuario, como el uso del ratón o cambiar el tamaño de una ventana; por cambios en el estado del entorno subyacente (por ejemplo, batería baja o eventos multimedia del sistema operativo) y por otras causas.
Cada evento se representa mediante un objeto basado en la interfaz Event, que puede incluir campos o funciones personalizados adicionales con información sobre lo ocurrido. La documentación de cada evento incluye una tabla (cerca del principio) con un enlace a la interfaz del evento asociada y otros datos relevantes. Encontrarás la lista completa de los distintos tipos de evento en Event > Interfaces basadas en Event.
Este tema ofrece un índice de los principales tipos de eventos que pueden interesarte (animación, portapapeles, workers, etc.), junto con las clases principales que implementan esos tipos de eventos.
Índice de eventos
| Tipo de evento | Descripción | Documentación |
|---|---|---|
| Animación |
Eventos relacionados con la Web Animation API. Se utilizan para responder a cambios en el estado de una animación (por ejemplo, cuando empieza o termina). |
Eventos de animación que se disparan en
Document,
Window
y
HTMLElement.
|
| Obtención asíncrona de datos | Eventos relacionados con la obtención de datos. |
Eventos que se disparan en
AbortSignal,
XMLHttpRequest
y
FileReader.
|
| Portapapeles |
Eventos relacionados con la API del portapapeles. Sirven para avisar cuando se corta, se copia o se pega contenido. |
Eventos que se disparan en
Document,
Element
y
Window.
|
| Composición |
Eventos relacionados con la composición: la introducción de texto de forma "indirecta" (es decir, sin pulsaciones normales de teclado). Por ejemplo, texto introducido a través de un motor de conversión de voz a texto, o mediante combinaciones de teclas especiales que modifican las pulsaciones del teclado para representar caracteres nuevos de otro idioma. |
Eventos que se disparan en
Element.
|
| Transición CSS |
Eventos relacionados con las transiciones CSS. Notifican cuando una transición CSS empieza, se detiene, se cancela, etc. |
Eventos que se disparan en
Document,
HTMLElement
y
Window.
|
| Base de datos |
Eventos relacionados con las operaciones de base de datos: apertura, cierre, transacciones, errores, etc. |
Eventos que se disparan en
IDBDatabase,
IDBOpenDBRequest,
IDBRequest
e
IDBTransaction.
|
| Mutación del DOM |
Eventos relacionados con las modificaciones de la jerarquía y los nodos del Modelo de Objetos del Documento (DOM). |
Advertencia: Los eventos de mutación están obsoletos. En su lugar, debes usar los observadores de mutaciones. |
| Arrastrar y soltar, rueda del ratón |
Eventos relacionados con el uso de la API de arrastrar y soltar de HTML y de los eventos de rueda. Los eventos de arrastre y de rueda derivan de los eventos de ratón. Aunque se disparan al usar la rueda del ratón o al arrastrar y soltar, también pueden usarse con otro hardware adecuado. |
Eventos de arrastre que se disparan en
Eventos de rueda que se disparan en
|
| Foco |
Eventos relacionados con los elementos que reciben y pierden el foco. |
Eventos que se disparan en
Element
y
Window.
|
| Formulario |
Eventos relacionados con la construcción, el restablecimiento y el envío de formularios. |
Eventos que se disparan en
HTMLFormElement.
|
| Pantalla completa |
Eventos relacionados con la API de pantalla completa. Avisan cuando se pasa del modo de pantalla completa al modo ventana (y al revés), y también de los errores que se produzcan durante esa transición. |
Eventos que se disparan en
Document
y
Element.
|
| Gamepad |
Eventos relacionados con la API Gamepad. |
Eventos que se disparan en
Window.
|
| Gestos |
Se recomienda usar los eventos táctiles para implementar gestos. |
Eventos que se disparan en
Además, existen varios eventos de gestos no estándar:
|
| Historial |
Eventos relacionados con la API del historial. |
Eventos que se disparan en
Window.
|
| Gestión de la visualización del contenido de elementos HTML |
Eventos relacionados con el cambio de estado de un elemento de visualización o de texto. |
Eventos que se disparan en
HTMLDetailsElement,
HTMLDialogElement
y
HTMLSlotElement.
|
| Entradas |
Eventos relacionados con los elementos de entrada de HTML, por
ejemplo |
Eventos que se disparan en
HTMLElement
y
HTMLInputElement.
|
| Teclado |
Eventos relacionados con el uso de un teclado. Avisan cuando se presiona una tecla, se suelta o simplemente se pulsa. |
Eventos que se disparan en
Document
y
Element.
|
| Carga y descarga de documentos |
Eventos relacionados con la carga y la descarga de documentos. |
|
| Manifiestos |
Eventos relacionados con la instalación de manifiestos de aplicaciones web progresivas. |
Eventos que se disparan en
Window.
|
| Multimedia |
Eventos relacionados con el uso de contenido multimedia (incluidas la API de Media Capture and Streams, la API Web Audio, la API Picture-in-Picture, etc.). |
Eventos que se disparan en
ScriptProcessorNode,
HTMLMediaElement,
AudioTrackList,
AudioScheduledSourceNode,
MediaRecorder,
MediaStream,
MediaStreamTrack,
VideoTrackList,
HTMLTrackElement,
OfflineAudioContext,
TextTrack,
TextTrackList,
Element/audio
y
Element/video.
|
| Mensajería |
Eventos relacionados con una ventana que recibe un mensaje de otro contexto de navegación. |
Eventos que se disparan en
Window.
|
| Ratón |
Eventos relacionados con el uso de un ratón. Se utilizan para notificar acciones como hacer clic, doble clic, presionar y soltar botones, hacer clic con el botón derecho, movimiento dentro y fuera de un elemento, selección de texto, etc. Los eventos de puntero ofrecen una alternativa independiente del hardware a los eventos de ratón. Los eventos de arrastre y de rueda derivan de los eventos de ratón. |
Eventos de ratón que se disparan en
Element
|
| Red y conexión |
Eventos relacionados con el establecimiento y la pérdida de la conexión de red. |
Eventos que se disparan en
Eventos que se disparan en
|
| Pagos |
Eventos relacionados con la API Payment Request. |
Eventos que se disparan en
|
| Rendimiento |
Eventos relacionados con cualquier especificación de rendimiento incluida en las API de rendimiento. |
Eventos que se disparan en
|
| Puntero |
Eventos relacionados con la API de eventos de puntero. Ofrece notificaciones independientes del hardware procedentes de dispositivos señaladores, como el ratón, la pantalla táctil o el lápiz óptico. |
Eventos que se disparan en
Document
y
HTMLElement.
|
| Impresión | Eventos relacionados con la impresión. |
Eventos que se disparan en
Window.
|
| Rechazo de promesas |
Eventos que se envían al contexto global del script cuando se rechaza cualquier promesa de JavaScript. |
Eventos que se disparan en
Window.
|
| Sockets |
Eventos relacionados con la API WebSockets. |
Eventos que se disparan en
WebSocket.
|
| SVG | Eventos relacionados con las imágenes SVG. |
Eventos que se disparan en
|
| Selección de texto |
Eventos de la API Selection relacionados con la selección de texto. |
Evento ( |
| Táctil |
Eventos relacionados con la API de eventos táctiles. Ofrece eventos de notificación al interactuar con una pantalla táctil (es decir, con un dedo o un lápiz). No guarda relación con la API Force Touch. |
Eventos que se disparan en
Document
y
Element.
|
| Realidad virtual |
Eventos relacionados con la API WebXR Device.
Advertencia: La
API WebVR y los
eventos de |
Eventos que se disparan en
XRSystem,
XRSession
y
XRReferenceSpace.
|
| RTC (comunicación en tiempo real) |
Eventos relacionados con la API WebRTC. |
Eventos que se disparan en
RTCDataChannel,
RTCDTMFSender,
RTCIceTransport
y
RTCPeerConnection.
|
| Eventos enviados por el servidor |
Eventos relacionados con la API de eventos enviados por el servidor. |
Eventos que se disparan en
EventSource.
|
| Voz |
Eventos relacionados con la API Web Speech. |
Eventos que se disparan en
SpeechSynthesisUtterance.
|
| Workers |
Eventos relacionados con la API Web Workers, la API Service Worker, la API Broadcast Channel y la API Channel Messaging. Sirven para responder a mensajes nuevos y a errores en el envío de mensajes. Los service workers también pueden recibir otros eventos, como notificaciones push, clics de los usuarios en las notificaciones mostradas, la invalidación de una suscripción push, la eliminación de elementos del índice de contenido, etc. |
Eventos que se disparan en
ServiceWorkerGlobalScope,
DedicatedWorkerGlobalScope,
SharedWorkerGlobalScope,
WorkerGlobalScope,
Worker,
BroadcastChannel
y
MessagePort.
|
Crear y despachar eventos
Además de los eventos disparados por las interfaces integradas, puedes crear y despachar eventos del DOM por tu cuenta. Estos eventos se denominan comúnmente eventos sintéticos, en contraposición a los eventos disparados por el navegador.
Crear eventos personalizados
Los eventos se pueden crear con el constructor Event de esta manera:
const event = new Event("build");
// Escucha el evento.
elem.addEventListener("build", (e) => {
/* … */
});
// Despacha el evento.
elem.dispatchEvent(event);
Este ejemplo de código usa el método EventTarget.dispatchEvent().
Añadir datos personalizados: CustomEvent()
Para añadir más datos al objeto del evento existe la interfaz CustomEvent, cuya propiedad detail permite pasar datos personalizados. Por ejemplo, el evento podría crearse así:
const event = new CustomEvent("build", { detail: elem.dataset.time });
Así podrás acceder a los datos adicionales desde el detector de eventos:
function eventHandler(e) {
console.log(`La hora es: ${e.detail}`);
}
Añadir datos personalizados: crear una subclase de Event
La interfaz Event también permite crear subclases. Esto resulta especialmente útil para la reutilización, para manejar datos personalizados más complejos o incluso para añadir métodos al evento.
class BuildEvent extends Event {
#buildTime;
constructor(buildTime) {
super("build");
this.#buildTime = buildTime;
}
get buildTime() {
return this.#buildTime;
}
}
Este ejemplo de código define una clase BuildEvent con una propiedad de solo lectura y un tipo de evento fijo.
Después, el evento se podría crear así:
const event = new BuildEvent(elem.dataset.time);
Los datos adicionales se pueden leer entonces en los detectores de eventos mediante las propiedades personalizadas:
function eventHandler(e) {
console.log(`La hora es: ${e.buildTime}`);
}
Burbujeo de eventos
A menudo conviene disparar un evento desde un elemento hijo y que lo capture un ancestro; opcionalmente, puedes incluir datos con el evento:
<form>
<textarea></textarea>
</form>
const form = document.querySelector("form");
const textarea = document.querySelector("textarea");
// Crea un evento nuevo, permite el burbujeo y proporciona los datos que quieras pasar a la propiedad "detail"
const eventAwesome = new CustomEvent("awesome", {
bubbles: true,
detail: { text: () => textarea.value },
});
// El elemento form escucha el evento personalizado "awesome" y luego muestra en la consola el resultado del método text() que se le pasó
form.addEventListener("awesome", (e) => console.log(e.detail.text()));
// Mientras el usuario escribe, el textarea dentro del formulario despacha (dispara) el evento, usando el propio textarea como punto de partida
textarea.addEventListener("input", (e) => e.target.dispatchEvent(eventAwesome));
Crear y despachar eventos de forma dinámica
Los elementos pueden escuchar eventos que aún no se han creado:
<form>
<textarea></textarea>
</form>
const form = document.querySelector("form");
const textarea = document.querySelector("textarea");
form.addEventListener("awesome", (e) => console.log(e.detail.text()));
textarea.addEventListener("input", function () {
// Crea y despacha (dispara) un evento al vuelo
// Nota: opcionalmente, también hemos usado una "expresión de función" (en lugar de una "expresión de función flecha") para que "this" represente al elemento
this.dispatchEvent(
new CustomEvent("awesome", {
bubbles: true,
detail: { text: () => textarea.value },
}),
);
});
Disparar eventos integrados
Este ejemplo muestra cómo simular un clic (es decir, generar un evento de clic mediante código) en una casilla de verificación con métodos del DOM. Mira el ejemplo en acción.
function simulateClick() {
const event = new MouseEvent("click", {
view: window,
bubbles: true,
cancelable: true,
});
const cb = document.getElementById("checkbox");
const cancelled = !cb.dispatchEvent(event);
if (cancelled) {
// Un manejador llamó a preventDefault.
alert("cancelado");
} else {
// Ningún manejador llamó a preventDefault.
alert("no cancelado");
}
}
Registrar manejadores de eventos
Hay dos formas recomendadas de registrar manejadores. El código de un manejador de eventos puede ejecutarse cuando se dispara un evento, ya sea asignándolo a la propiedad onevent correspondiente del elemento de destino o registrándolo como detector del elemento con el método addEventListener(). En ambos casos, el manejador recibirá un objeto que implementa la interfaz Event (o una interfaz derivada). La diferencia principal es que, con los métodos de los detectores de eventos, se pueden añadir (o quitar) varios manejadores.
Advertencia: Existe un tercer enfoque para definir manejadores de eventos, el de los atributos HTML onevent, ¡pero no se recomienda! Inflan el marcado, lo hacen menos legible y dificultan la depuración. Para más información, consulta manejadores de eventos en línea.
Usar las propiedades onevent
Por convención, los objetos de JavaScript que disparan eventos tienen las propiedades "onevent" correspondientes (cuyo nombre se forma anteponiendo "on" al nombre del evento). Estas propiedades se invocan para ejecutar el código del manejador asociado cuando se dispara el evento, y también puede invocarlas directamente tu propio código.
Para definir el código de un manejador de eventos, basta con asignarlo a la propiedad onevent adecuada. Solo se puede asignar un manejador de eventos por cada evento en un elemento. Si hace falta, se puede reemplazar el manejador asignando otra función a la misma propiedad.
El siguiente ejemplo muestra cómo asignar una función greet() al evento click mediante la propiedad onclick.
const btn = document.querySelector("button");
function greet(event) {
console.log("greet:", event);
}
btn.onclick = greet;
Ten en cuenta que al manejador de eventos se le pasa como primer argumento un objeto que representa el evento. Este objeto implementa la interfaz Event o deriva de ella.
EventTarget.addEventListener
La forma más flexible de definir un manejador de eventos en un elemento es usar el método EventTarget.addEventListener. Este enfoque permite asignar varios detectores a un elemento y, si es necesario, eliminarlos con EventTarget.removeEventListener.
Nota: Poder añadir y eliminar manejadores de eventos permite, por ejemplo, que un mismo botón realice acciones distintas según las circunstancias. Además, en programas más complejos, eliminar los manejadores antiguos o que ya no se usan puede mejorar la eficiencia.
El siguiente ejemplo muestra cómo definir una función greet() como detector (o manejador de eventos) del evento click (si lo prefieres, puedes usar una expresión de función anónima en lugar de una función con nombre). Recuerda de nuevo que el evento se pasa como primer argumento al manejador de eventos.
const btn = document.querySelector("button");
function greet(event) {
console.log("greet:", event);
}
btn.addEventListener("click", greet);
El método también acepta argumentos u opciones adicionales para controlar cómo se capturan y se quitan los eventos. Encontrarás más información en la página de referencia de EventTarget.addEventListener.
Usar AbortSignal
Una característica destacable de los detectores de eventos es que se puede usar una señal de aborto para limpiar varios manejadores de eventos a la vez.
Para ello, pasa el mismo AbortSignal a la llamada a addEventListener() de todos los manejadores de eventos que quieras poder quitar juntos. Después, llama a abort() en el controlador que posee ese AbortSignal y se quitarán todos los manejadores que se añadieron con esa señal. Por ejemplo, así se añade un manejador de eventos que podremos quitar con un AbortSignal:
const controller = new AbortController();
btn.addEventListener(
"click",
(event) => {
console.log("greet:", event);
},
{ signal: controller.signal },
); // pasa un AbortSignal a este manejador
Después, este manejador de eventos se puede quitar así:
controller.abort(); // quita todos los manejadores de eventos asociados a este controlador
Interacción entre varios manejadores de eventos
La propiedad IDL onevent (por ejemplo, element.onclick = ...) y el atributo de contenido HTML onevent (por ejemplo, <button onclick="...">) apuntan al mismo y único espacio para un manejador. El HTML se carga antes de que JavaScript pueda acceder al mismo elemento, así que normalmente JavaScript reemplaza lo que se haya especificado en HTML. Los manejadores añadidos con addEventListener() son independientes: usar onevent no elimina ni reemplaza los detectores añadidos con addEventListener(), y viceversa.
Cuando se despacha un evento, los detectores se invocan por fases. Hay dos: captura y burbujeo. En la fase de captura, el evento parte del elemento ancestro más alto y desciende por el árbol DOM hasta llegar al objetivo. En la fase de burbujeo, el evento se mueve en sentido contrario. Por defecto, los detectores de eventos escuchan en la fase de burbujeo, pero pueden escuchar en la de captura si se especifica capture: true en addEventListener(). Dentro de una misma fase, los detectores se ejecutan en el orden en que se registraron. El manejador onevent se registra la primera vez que deja de ser nulo; las reasignaciones posteriores solo cambian la función que se ejecuta, no su posición en el orden.
Llamar a Event.stopPropagation() impide que se invoquen los detectores de los demás elementos que queden más adelante en la cadena de propagación. Event.stopImmediatePropagation() impide además que se invoquen los detectores restantes del mismo elemento.
Especificaciones
| Especificación |
|---|
| DOM> # events> |
| HTML> # events-2> |