Introducción
Este artículo es la continuación de Eventos en JavaScript.
Objeto Event
Generalmente, los manejadores de eventos necesitan información adicional para procesar las tareas que tienen que realizar. Si una función procesa, por ejemplo, el evento click, es posible que necesite conocer la posición en la que estaba el ratón en el momento de realizar el click.
También es común es necesitar información adicional en los eventos del teclado. Por ejemplo, cuando pulsamos una tecla nos interesa saber cuál ha sido la tecla pulsada, o si tenemos a mayores alguna tecla especial pulsada como Alt
, Control
, etc.
Para gestionar toda esa información disponemos del objeto Event
, el cuál nos permitirá acceder a esas propiedades adicionales que se generan en los eventos.
Por ejemplo:
1
2
3
4
document.getElementById("unParrafo").addEventListener('click',gestionar,false);
const gestionar = (miEvento) => {
alert (miEvento.type); // Mostrará una alerta con el tipo de evento que en este caso es 'click'.
}
En el código del ejemplo anterior cuando se produce el evento de click
en un párrafo con id="unParrafo"
, durante la fase de burbujeo, se llamará a la función gestionar. En la función gestionar hemos creado un argumento que le llamamos miEvento
, y es justamente en ese argumento que hemos puesto en la función, dónde el navegador de forma automática, pondrá todos los datos referentes al evento que se ha disparado.
Una vez dentro de la función, mostramos una alerta con el tipo de evento (propiedad type
del objeto Event
) que se acaba de disparar.
Lee el artículo El objeto Event.
(Voluntario) Lee el artículo Escuchar eventos y handleEvent.
¿Podemos crear eventos personalizados en JavaScript sin el uso de bibliotecas externas?
¿Podemos disparar eventos desde código JavaScript?
Si.
¿Podemos añadir información adicional al crear un objeto Event de la siguiente manera: const event = new Event("click", { detail: 123 });
?
const event = new Event("click", { detail: 123 });
?No.
Propiedades y métodos del objeto Event
Propiedades del objeto Event:
altKey
,ctrlKey
,metaKey
,shiftKey
: Valor booleano que indica si están presionadas alguna de las teclasAlt
,Ctrl
,Meta
oShift
en el momento del evento.bubbles
: Valor booleano que indica si el evento burbujea o no.button
: Valor integer que indica que botón del ratón ha sido presionado o soltado, 0=izquierdo, 2=derecho, 1=medio.cancelable
: Valor booleano que indica si el evento se puede cancelar.charCode
: Indica el carácter Unicode de la tecla presionada.clientX
,clientY
: Devuelve las coordenadas de la posición del ratón en el momento del evento.currentTarget
: El elemento al que se asignó el evento. Por ejemplo si tenemos un evento de click en un divA que contiene un hijo divB. Si hacemos click en divB,currentTarget
referenciará a divA (el elemento dónde se asignó el evento) mientras quetarget
devolverá divB, el elemento dónde ocurrió el evento.eventPhase
: Un valor integer que indica la fase del evento que está siendo procesada. Fase de captura (1), en destino (2) o fase de burbujeo (3).layerX
,layerY
: Devuelve las coordenadas del ratón relativas a un elemento posicionado absoluta o relativamente. Si el evento ocurre fuera de un elemento posicionado se usará la esquina superior izquierda del documento.pageX
,pageY
: Devuelve las coordenadas del ratón relativas a la esquina superior izquierda de una página.relatedTarget
: En un evento de “mouseover” indica el nodo que ha abandonado el ratón. En un evento demouseout
indica el nodo hacia el que se ha movido el ratón.screenX
,screenY
: Devuelve las coordenadas del ratón relativas a la pantalla dónde se disparó el evento.target
: El elemento dónde se originó el evento, que puede diferir del elemento que tenga asignado el evento. VéasecurrentTarget
.timestamp
: Devuelve la hora (en milisegundos desdeepoch
) a la que se creó el evento. Por ejemplo cuando se presionó una tecla. No todos los eventos devuelventimestamp
.type
: Una cadena de texto que indica el tipo de eventoclick
,mouseout
,mouseover
, etc.which
: Indica el Unicode de la tecla presionada. Idéntico acharCode
, excepto que esta propiedad también funciona en Netscape 4.
Métodos del objeto Event:
preventDefault()
: Cancela cualquier acción asociada por defecto a un evento.stopPropagation()
: Evita que un evento burbujee. Por ejemplo si tenemos un divA que contiene un divB hijo. Cuando asignamos un evento de click a divA, si hacemos click en divB, por defecto se dispararía también el evento en divA en la fase de burbujeo. Para evitar ésto se puede llamar astopPropagation()
en divB. Para ello creamos un evento de click en divB y le hacemosstopPropagation()
.
Custom Events
Antes de seguir con la propagación y captura de eventos debemos entender qué son los Custom Events y para qué sirven.
Lee el artículo ¿Qué son los Custom Events?
Propagación y captura de eventos
Los eventos se propagan desde el elemento que los desencadena hacia sus elementos padre. Se puede capturar un evento durante esta propagación y realizar acciones diferentes según el elemento específico que lo desencadenó. Para detener la propagación de un evento a elementos padre, se usa event.stopPropagation()
.
1
2
3
4
5
<div id="padre">
<div id="hijo">
<button id="boton">Haz clic aquí</button>
</div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
document.getElementById('boton').addEventListener('click', function(event) {
alert('Haz clic en el botón hijo');
event.stopPropagation(); // Detiene la propagación del evento hacia arriba
});
document.getElementById('hijo').addEventListener('click', function(event) {
alert('Haz clic en el div hijo');
});
document.getElementById('padre').addEventListener('click', function(event) {
alert('Haz clic en el div padre');
});
La propagación de eventos permite que los eventos desencadenados en elementos hijos se propaguen hacia sus elementos padres. Esta característica es muy útil para enviar datos desde elementos hijos a sus elementos padres mediante eventos personalizados y es fundamental en el funcionamiento de los componentes en varios frameworks de JavaScript como React, Vue.js y Angular.
Existen 3 modelos propuestos de disparo de eventos, que clarificarán el orden de disparo de los mismos:
- Modelo de captura de eventos: En este modelo los eventos se van disparando de afuera hacia adentro. Es decir, primero se disparará el evento asignado al elemento exterior, y continúa descendiendo y disparando los eventos que coincidan, hasta llegar al elemento interior.
- Modelo de burbujeo de eventos: En este modelo los eventos se van disparando desde dentro hacia afuera. Es decir, primero se disparará el evento asignado al elemento interior, y continúa subiendo y disparando los eventos que coincidan, hasta llegar al elemento exterior.
- Modelo de W3C: En este modelo se integran los dos modelos anteriores. Simplemente se realiza la fase de captura de eventos primero y, cuando termina, se realiza la fase de burbujeo. En este modelo cuando registramos un evento con
addEventListener(<evento>, <función>, <true|false>)
tenemos la opción de indicar cuándo queremos que se dispare el evento:- En la fase de burbujeo, el evento se propaga desde el origen del evento hacia el documento raíz.
- En la fase de captura, el evento se propaga desde el documento raíz hasta el origen del evento.
- También disponemos de un método para cancelar eventos con
preventDefault()
, y de un método para detener la propagación de eventos en la fase de burbujeo, constopPropagation()
.
Lee el artículo Emisión de eventos.
Lee el artículo Propagación de eventos.
Enviar datos de hijos a padres con eventos personalizados
Los eventos personalizados se pueden utilizar para comunicar datos desde un componente hijo a un componente padre. A continuación se muestra un ejemplo de cómo se puede lograr esto en un entorno sin frameworks, utilizando la propagación de eventos del DOM:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Custom Event Example</title>
</head>
<body>
<div id="parent"></div>
<script>
// Crear el elemento hijo
const child = document.createElement('button');
child.textContent = 'Click me';
// Crear el elemento padre
const parent = document.getElementById('parent');
parent.appendChild(child);
// Añadir un evento personalizado al hijo
child.addEventListener('click', () => {
const customEvent = new CustomEvent('childEvent', {
bubbles: true, // para que se propague
detail: { message: 'Hello from child' }
});
child.dispatchEvent(customEvent);
});
// Añadir un listener en el padre para capturar el evento del hijo
parent.addEventListener('childEvent', (event) => {
console.log('Received message from child:', event.detail.message);
});
</script>
</body>
</html>
En este ejemplo:
- Elemento hijo (
child
): Cuando se hace clic en el botón, se dispara un evento personalizadochildEvent
con algunos datos en la propiedad detail. Elemento padre (
parent
): El padre escucha el eventochildEvent
y maneja los datos recibidos del hijo.- En React, los datos de un componente hijo se envían a un componente padre mediante la elevación del estado y callbacks, en lugar de utilizar directamente la propagación de eventos del DOM.
- En Vue.js, la comunicación de hijos a padres se realiza mediante la emisión de eventos personalizados.
- Angular también proporciona
@Output
que crea un evento que es capturado por el componente padre.
Ejercicio de eventos y propagación: https://jsfiddle.net/xxjcaxx/wep0c2j9/1/