From a83ad87fd85baac14094a3200f42bf5556a2bb47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Menj=C3=ADvar?= Date: Wed, 19 Aug 2020 22:46:20 -0700 Subject: [PATCH 01/20] First draft --- .../02-bubbling-and-capturing/article.es.md | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 2-ui/2-events/02-bubbling-and-capturing/article.es.md diff --git a/2-ui/2-events/02-bubbling-and-capturing/article.es.md b/2-ui/2-events/02-bubbling-and-capturing/article.es.md new file mode 100644 index 000000000..b4027b271 --- /dev/null +++ b/2-ui/2-events/02-bubbling-and-capturing/article.es.md @@ -0,0 +1,135 @@ +# Propagación y captura + +Vamos a empezar con un ejemplo. + +Este manejador está asignado a `
`, pero también es ejecutado si haces clic elemento anidado como `` ó ``: + +```html autorun height=60 +
+ Si haces clic enEM, el manejador en DIV es ejecutado. +
+``` + +¿No es un poco extraño? ¿Por qué el manejador en `
` es ejecutado, si el clic fue hecho en ``? + +# Propagación + +El principio de propagación es simple. + +**Cuando un evento ocurre en un elemento, este primero ejecuta los manejadores que tiene asignados, luego los manejadores de su padre, así hasta otros ancentros.** + +Dígamos que tenemos 3 elementos anidados `FORM > DIV > P` con un manejador en cada uno de ellos: + +```html run autorun + + +
FORM +
DIV +

P

+
+
+``` + +Un clic en el elemento `

` primero ejecuta `onclick`: +1. En ese `

`. +2. Luego en el `

` de arriba. +3. Luego en el `
` de más arriba. +4. Y así sucesivamente hasta el objeto `document`. + +![](event-order-bubbling.svg) + +Si hacemos clic en `

`, entonces veremos 3 alertas: `p` -> `div` -> `form`. + +Este proceso se conoce como "propagación", porque los eventos "se propagan" desde el elemento más al interior a través de los padres como una burbujas en el agua. + +```warn header="*Almost* all events bubble." +La palabra clave en esta frase es "casi". + + +Por ejemplo, un evento `focus` no se propaga. Hay otros ejemplos también, los veremos. Pero aún así, esta es la excepción a la regla, la mayoría de eventos sí se propagan. +``` + +## event.target + +Un manejado en un elemento padre puede siempre obtener los detalles sobre dónde el evento ocurrió. + +**El elemento anidado más profundo que causó el evento es llamado elemento *objetivo*, accesible como `event.target`** + +Nota la diferencia de `this` (=`event.currentTarget`): + +- `event.target` -- es el elemento "objetivo" que inició el evento, no cambia a través de todo el proceso de propagación. +- `this` -- es el elemento "actual", el que tiene un manejador ejecutándose en el momento. + +Por ejemplo, si tenemos un solo manejador `form.onclick`, este puede `atrapar` todos los clicks dentro del formulario. No importa dónde el clic se dio, se propaga hasta el `` y ejecuta el manejador. + +En el manejador `form.onclick`: + +- `this` (=`event.currentTarget`) es el elemento ``, porque el manejador se ejecuto en él. +- `event.target` es el elemento actual dentro de el formulario al que se le dio clic. + +Mira esto: + +[codetabs height=220 src="bubble-target"] + +Es posible que `event.target` sea igual a `this` -- ocurre cuando el clic se da directamente en el elemento ``. + +## Detener la propagación + +Una propagación de evento va desde el elemento objetivo hacia arriba. Normalmente este continua hasta `` y luego hacia el objeto `document`, algunos eventos incluso alcanzan `window`, llamando a todos los manejadores en el camino. + +Pero cualquier manejador podría decidir que el evento se ha procesado por completo y detener su propagación. + +El método para esto es `event.stopPropagation()`. + +Por ejemplo, aquí `body.onclick` no funciona si haces clic en ` + +``` + +```smart header="event.stopImmediatePropagation()" +Si un elemento tiene multiples manejadores para un solo evento, aunque uno de ellos detenga la propagación, los demás aún se ejecutarán. + +En otras palabras, `event.stopPropagation()` detiene la propagación hacia arriba, pero en el elemento actual todos los manejadores se ejecutarán. + +Para detener la propagación y prevenir que los manejadores de el elemento actual se ejecuten, hay un método `event.stopImmediatePropagation()`. Después de él, ningún otro manejador será ejecutado. +``` + +```warn header="Don't stop bubbling without a need!" +La propagación es conveniente. No la detengas sin una necesidad real: obvia y arquitectónicamente bien pensada. + +A veces `event.stopPropagation()` crea trampas ocultas que luego se convierten en problemas. + +Por ejemplo: + +1. Creamos un menú anidado. Cada submenú maneja los clics en sus elementos y ejecuta `stopPropagation` para que el menu de arriba no se desencadene. +2. Luego decidimos atrapar los clic en toda la ventana, para seguir el rastro del comportamiento del usuario (donde dan clic). Algunos sistemas de análisis hacen eso. Usualmente el código usa `document.addEventListener('click'…)` para atrapar todos los clics. +3. Nuestro análisis no funcionará sobre el área dónde los clics son detenidos por `stopPropagation`. Tristemente, tenemos una "zona muerta". + +Usualmente no hay una necesidad real para prevenir la propagación. Una tarea que aparentemente requiere que sea resuelto por otros medios. Uno de ellas es usar eventos personalizados, cubriremos eso más tarde. También podemos escribir nuestros datos en el objeto `event` en un manejador y leerlo en otro (manejador), para así poder pasar a los manejadores en los padres información sobre el proceso de abajo. +``` + +## Captura + +Hay otra fase en el procesamiento de eventos llamada "captura". Es raro usarla en código real, pero a veces puede ser útil. + +Los [eventos del DOM](http://www.w3.org/TR/DOM-Level-3-Events/) estándar describen 3 fases de la propagación de eventos: + +1. Fase de captura -- el evento desciende al elemento. +2. Fase de objetivo -- el evento alcanza al elemento. +3. Fase de propagación -- el evento se propaga hacia arriba del elemento. + +Aquí está la imagen de un clic en `` dentro de una tabla, tomada desde la específicación: + +![](eventflow.svg) + +Eso es: por un clic en `` el evento primera va a través de la cadena de ancestros hacia el elemento (fase de captura), luego alcanza el objetivo y se desendena ahí (fase de objetivo), y por último va hacia arriba (fase de propagación), ejecutando los manejadores en su camino. + +**Antes solo hablamos de la propagación, porque la fase de captura es raramente usada. Normalmente es invisible a nosotros.** From 7dcb92f0e094af3d430b685f5f16b96aea7aae67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Menj=C3=ADvar?= Date: Thu, 20 Aug 2020 22:28:18 -0700 Subject: [PATCH 02/20] Second draft: complete article --- .../02-bubbling-and-capturing/article.es.md | 132 +++++++++++++++--- 1 file changed, 110 insertions(+), 22 deletions(-) diff --git a/2-ui/2-events/02-bubbling-and-capturing/article.es.md b/2-ui/2-events/02-bubbling-and-capturing/article.es.md index b4027b271..33b180a37 100644 --- a/2-ui/2-events/02-bubbling-and-capturing/article.es.md +++ b/2-ui/2-events/02-bubbling-and-capturing/article.es.md @@ -2,10 +2,10 @@ Vamos a empezar con un ejemplo. -Este manejador está asignado a `

`, pero también es ejecutado si haces clic elemento anidado como `` ó ``: +Este manejador está asignado a `
`, pero también se ejecuta si haces clic a cualquier elemento anidado como `` ó ``: ```html autorun height=60 -
+
Si haces clic enEM, el manejador en DIV es ejecutado.
``` @@ -16,7 +16,7 @@ Este manejador está asignado a `
`, pero también es ejecutado si haces cli El principio de propagación es simple. -**Cuando un evento ocurre en un elemento, este primero ejecuta los manejadores que tiene asignados, luego los manejadores de su padre, así hasta otros ancentros.** +**Cuando un evento ocurre en un elemento, este primero ejecuta los manejadores que tiene asignados, luego los manejadores de su padre, y así hasta otros ancentros.** Dígamos que tenemos 3 elementos anidados `FORM > DIV > P` con un manejador en cada uno de ellos: @@ -35,7 +35,7 @@ Dígamos que tenemos 3 elementos anidados `FORM > DIV > P` con un manejador en c ``` -Un clic en el elemento `

` primero ejecuta `onclick`: +Un clic en el elemento del interior `

` primero ejecuta `onclick`: 1. En ese `

`. 2. Luego en el `

` de arriba. 3. Luego en el `
` de más arriba. @@ -43,11 +43,11 @@ Un clic en el elemento `

` primero ejecuta `onclick`: ![](event-order-bubbling.svg) -Si hacemos clic en `

`, entonces veremos 3 alertas: `p` -> `div` -> `form`. +Así si hacemos clic en `

`, entonces veremos 3 alertas: `p` -> `div` -> `form`. -Este proceso se conoce como "propagación", porque los eventos "se propagan" desde el elemento más al interior a través de los padres como una burbujas en el agua. +Este proceso se conoce como "propagación" porqué los eventos "se propagan" desde el elemento más al interior, a través de los padres, como una burbujas en el agua. -```warn header="*Almost* all events bubble." +```warn header="*Casi* todos los elementos se propagan." La palabra clave en esta frase es "casi". @@ -56,7 +56,7 @@ Por ejemplo, un evento `focus` no se propaga. Hay otros ejemplos también, los v ## event.target -Un manejado en un elemento padre puede siempre obtener los detalles sobre dónde el evento ocurrió. +Un manejador en un elemento padre siempre puede obtener los detalles sobre dónde realmente ocurrió el evento. **El elemento anidado más profundo que causó el evento es llamado elemento *objetivo*, accesible como `event.target`** @@ -65,22 +65,22 @@ Nota la diferencia de `this` (=`event.currentTarget`): - `event.target` -- es el elemento "objetivo" que inició el evento, no cambia a través de todo el proceso de propagación. - `this` -- es el elemento "actual", el que tiene un manejador ejecutándose en el momento. -Por ejemplo, si tenemos un solo manejador `form.onclick`, este puede `atrapar` todos los clicks dentro del formulario. No importa dónde el clic se dio, se propaga hasta el `` y ejecuta el manejador. +Por ejemplo, si tenemos un solo manejador `form.onclick`, este puede `atrapar` todos los clicks dentro del formulario. No importa dónde el clic se hizo, se propaga hasta el `` y ejecuta el manejador. En el manejador `form.onclick`: -- `this` (=`event.currentTarget`) es el elemento ``, porque el manejador se ejecuto en él. -- `event.target` es el elemento actual dentro de el formulario al que se le dio clic. +- `this` (=`event.currentTarget`) es el elemento ``, porque el manejador se ejecutó en él. +- `event.target` es el elemento actual dentro de el formulario al que se le hizo clic. Mira esto: [codetabs height=220 src="bubble-target"] -Es posible que `event.target` sea igual a `this` -- ocurre cuando el clic se da directamente en el elemento ``. +Es posible que `event.target` sea igual a `this` -- ocurre cuando el clic se hace directamente en el elemento ``. ## Detener la propagación -Una propagación de evento va desde el elemento objetivo hacia arriba. Normalmente este continua hasta `` y luego hacia el objeto `document`, algunos eventos incluso alcanzan `window`, llamando a todos los manejadores en el camino. +Una propagación de evento empieza desde el elemento objetivo hacia arriba. Normalmente este continua hasta `` y luego hacia el objeto `document`, algunos eventos incluso alcanzan `window`, llamando a todos los manejadores en el camino. Pero cualquier manejador podría decidir que el evento se ha procesado por completo y detener su propagación. @@ -90,37 +90,37 @@ Por ejemplo, aquí `body.onclick` no funciona si haces clic en ` + ``` ```smart header="event.stopImmediatePropagation()" Si un elemento tiene multiples manejadores para un solo evento, aunque uno de ellos detenga la propagación, los demás aún se ejecutarán. -En otras palabras, `event.stopPropagation()` detiene la propagación hacia arriba, pero en el elemento actual todos los manejadores se ejecutarán. +En otras palabras, `event.stopPropagation()` detiene la propagación hacia arriba, pero todos los manejadores en el elemento actual se ejecutarán. Para detener la propagación y prevenir que los manejadores de el elemento actual se ejecuten, hay un método `event.stopImmediatePropagation()`. Después de él, ningún otro manejador será ejecutado. ``` -```warn header="Don't stop bubbling without a need!" -La propagación es conveniente. No la detengas sin una necesidad real: obvia y arquitectónicamente bien pensada. +```warn header="¡No detengas la propagación sino es necesario!" +La propagación es conveniente. No la detengas sin una necesidad real, obvia y arquitectónicamente bien pensada. A veces `event.stopPropagation()` crea trampas ocultas que luego se convierten en problemas. Por ejemplo: 1. Creamos un menú anidado. Cada submenú maneja los clics en sus elementos y ejecuta `stopPropagation` para que el menu de arriba no se desencadene. -2. Luego decidimos atrapar los clic en toda la ventana, para seguir el rastro del comportamiento del usuario (donde dan clic). Algunos sistemas de análisis hacen eso. Usualmente el código usa `document.addEventListener('click'…)` para atrapar todos los clics. +2. Luego decidimos atrapar los clic en toda la ventana, para seguir el rastro del comportamiento del usuario (dónde hacen clic). Algunos sistemas de análisis hacen eso. Usualmente el código usa `document.addEventListener('click'…)` para atrapar todos los clics. 3. Nuestro análisis no funcionará sobre el área dónde los clics son detenidos por `stopPropagation`. Tristemente, tenemos una "zona muerta". -Usualmente no hay una necesidad real para prevenir la propagación. Una tarea que aparentemente requiere que sea resuelto por otros medios. Uno de ellas es usar eventos personalizados, cubriremos eso más tarde. También podemos escribir nuestros datos en el objeto `event` en un manejador y leerlo en otro (manejador), para así poder pasar a los manejadores en los padres información sobre el proceso de abajo. +Usualmente no hay una necesidad real para prevenir la propagación. Una tarea que aparentemente requiere que sea resuelto por otros medios. Uno de ellas es usar eventos personalizados, cubriremos eso más tarde. También podemos escribir nuestros datos en el objeto `event` en un manejador y leerlo en otro, para así poder pasar información sobre el proceso de abajo a los manejadores en los padres. ``` ## Captura Hay otra fase en el procesamiento de eventos llamada "captura". Es raro usarla en código real, pero a veces puede ser útil. -Los [eventos del DOM](http://www.w3.org/TR/DOM-Level-3-Events/) estándar describen 3 fases de la propagación de eventos: +El estándar de [eventos del DOM](http://www.w3.org/TR/DOM-Level-3-Events/) describe 3 fases de la propagación de eventos: 1. Fase de captura -- el evento desciende al elemento. 2. Fase de objetivo -- el evento alcanza al elemento. @@ -130,6 +130,94 @@ Aquí está la imagen de un clic en `` dentro de una tabla, tomada desde la ![](eventflow.svg) -Eso es: por un clic en `` el evento primera va a través de la cadena de ancestros hacia el elemento (fase de captura), luego alcanza el objetivo y se desendena ahí (fase de objetivo), y por último va hacia arriba (fase de propagación), ejecutando los manejadores en su camino. +Se explica así: por un clic en `` el evento va primero a través de la cadena de ancestros hacia el elemento (fase de captura), luego alcanza el objetivo y se desendena ahí (fase de objetivo), y por último va hacia arriba (fase de propagación), ejecutando los manejadores en su camino. -**Antes solo hablamos de la propagación, porque la fase de captura es raramente usada. Normalmente es invisible a nosotros.** +**Antes solo hablamos de la propagación porque la fase de captura es raramente usada. Normalmente es invisible a nosotros.** + +Los manejadores agregados usando `on`-propiedad ó usando atributos HTML ó `addEventListener(event, handler)` con dos argumentos no ejecutarán la fase de captura, únicamente ejecutarán la 2da y 3ra fase. + +Para atrapar un evento en la fase de captura, necesitamos preparar la opción `capture` como `true` en el manejador: + +```js +elem.addEventListener(..., {capture: true}) +// o, solo "true" es una forma más corta de {capture: true} +elem.addEventListener(..., true) +``` + +Hay dos posibles valores para la opción `capture`: + +- Si es `false` (por defecto), entonces el manejador es preparado para la fase de propagación. +- Si es `true`, entonces el manejador es preparado para la fase de captura. + +Es de notar que mientras formalmente hay 3 fases, la 2da fase ("la fase de objetivo": el evento alcanzó el elemento) no es manejada de forma separada; los manejadores en ambas fases, la de captura y propagación, se disparan en esa fase. + +Veamos ambas fases, captura y propagación, en acción: + +```html run autorun height=140 edit + + +FORM +

DIV +

P

+
+
+ + +``` + +El código prepara manejadores de clic en *cada* elemento en el documento para ver cuáles están funcionando. + +Si haces clic en `

`, verás que la secuencia es: + +1. `HTML` -> `BODY` -> `FORM` -> `DIV` (fase de captura, el primer detector): +2. `P` (fase de objetivo, se dispara dos veces, tan pronto como preparemos los dos detectores: de captura y propagación) +3. `DIV` -> `FORM` -> `BODY` -> `HTML` (fase de propagación, el segundo detector). + +Hay un propiedad `event.eventPhase` que nos dice el número de fase en la qué el evento fue capturado. Pero es raramente usada, ya que usualmente lo sabemos en el manejador. + +```smart header="Para quitar el manejador, `removeEventListener` necesita la misma fase" +Si nosotros `addEventListener(..., true)`, entonces deberíamos mencionar la misma fase en `removeEventListener(..., true)` para remover el manejador correctamente. +``` + +````smart header="Detectores de eventos en el mismo elemento y en la misma fase se ejecutan en el orden de asignación" +Si tenemos multiples manejadores de eventos en la misma fase, asignados al mismo elemento con `addEventListener`, se ejecutarán en el orden que fueron creados: + +```js +elem.addEventListener("click", e => alert(1)); // garantizado que se ejecutara primero +elem.addEventListener("click", e => alert(2)); +``` +```` + +## Resumen + +Cuando un evento ocurre -- el más anidado elemento dónde ocurrió se reconoce como el "elemento objetivo" (`event.target`). + +- Luego el evento se mueve hacia abajo desde el documento raíz hacia `event.target`, llamando a los manejadores en el camino asignados con `addEventListener(..., true)` (`true` es una abreviación para `{captura: true}`). +- Luego los manejadores son llamados en el elemento objetivo mismo. +- Luego el evento se propaga hacia arriba desde `event.target` hacia la raíz, llamando a los manejadores que se asignaron usando `on` and `addEventListener` sin el 3er argumento o con el 3er argumento `false/{capture:false}`. + +Cada manejador puede acceder a las propiedades del objeto `event`: + +- `event.target` -- el elemento más profundo que originó el evento. +- `event.currentTarget` (=`this`) -- el elemento actual que maneja el evento (el qué tiene al manejador en él) +- `event.eventPhase` -- la fase actual (captura=1, objetivo=2, propagación=3). + +Cualquier manejador de evento puede detener el evento al llamar `event.stopPropagation()`, pero no es recomendado porque no podemos realmente asegurar que no lo necesitaremos más adelante, quizá para completar diferentes cosas. + +La fase de captura raramente es usada, usualmente manejamos los evento en propagación. Y hay una lógica atrás de eso. + +En el mundo real, cuando un accidente ocurre, las autoridades locales reaccionan primero. Ellos conocen mejor el área dónde ocurrió. Luego, si es necesario, autoridades de alto nível. + +Lo mismo para los manejadores de eventos. El código que se prepara en el manejador de un elemento en particular conoce el máximo de detalles sobre el elemento y qué hace. Un manejador en un `` particular puede ser adecuado para ese exacto ``, conocer todo sobre él, entonces debe tener su oportunidad primero. Lueog su padre inmediato también conoce sobre el contexto, pero un poco menos, y así sucesivamente hasta el elemento de arriba que maneja conceptos generales y se ejecuta al final. + +La propagación y captura ponen los cimientos para "delegación de eventos" -- un extremadamente poderoso patrón de manejo de eventos que se estudia en el siguiente capítulo. \ No newline at end of file From d57dc71db99b3714dcfef5f2f7695cdf5e758345 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Menj=C3=ADvar?= Date: Wed, 2 Sep 2020 22:24:38 -0700 Subject: [PATCH 03/20] Translate html example --- .../02-bubbling-and-capturing/bubble-target.view/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/2-ui/2-events/02-bubbling-and-capturing/bubble-target.view/index.html b/2-ui/2-events/02-bubbling-and-capturing/bubble-target.view/index.html index 8313ec29f..31e3573e6 100644 --- a/2-ui/2-events/02-bubbling-and-capturing/bubble-target.view/index.html +++ b/2-ui/2-events/02-bubbling-and-capturing/bubble-target.view/index.html @@ -7,7 +7,7 @@ - A click shows both event.target and this to compare: + Un clic muestra ambos, el event.target y this para comparar:

FORM
DIV From 4d80c90d8cc752fed8f8346a8a6c52e5b9f51c53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Menj=C3=ADvar?= Date: Wed, 2 Sep 2020 22:26:49 -0700 Subject: [PATCH 04/20] Review article.md translation --- .../02-bubbling-and-capturing/article.es.md | 223 ------------------ .../02-bubbling-and-capturing/article.md | 190 ++++++++------- 2 files changed, 94 insertions(+), 319 deletions(-) delete mode 100644 2-ui/2-events/02-bubbling-and-capturing/article.es.md diff --git a/2-ui/2-events/02-bubbling-and-capturing/article.es.md b/2-ui/2-events/02-bubbling-and-capturing/article.es.md deleted file mode 100644 index 33b180a37..000000000 --- a/2-ui/2-events/02-bubbling-and-capturing/article.es.md +++ /dev/null @@ -1,223 +0,0 @@ -# Propagación y captura - -Vamos a empezar con un ejemplo. - -Este manejador está asignado a `
`, pero también se ejecuta si haces clic a cualquier elemento anidado como `` ó ``: - -```html autorun height=60 -
- Si haces clic enEM, el manejador en DIV es ejecutado. -
-``` - -¿No es un poco extraño? ¿Por qué el manejador en `
` es ejecutado, si el clic fue hecho en ``? - -# Propagación - -El principio de propagación es simple. - -**Cuando un evento ocurre en un elemento, este primero ejecuta los manejadores que tiene asignados, luego los manejadores de su padre, y así hasta otros ancentros.** - -Dígamos que tenemos 3 elementos anidados `FORM > DIV > P` con un manejador en cada uno de ellos: - -```html run autorun - - -FORM -
DIV -

P

-
- -``` - -Un clic en el elemento del interior `

` primero ejecuta `onclick`: -1. En ese `

`. -2. Luego en el `

` de arriba. -3. Luego en el `
` de más arriba. -4. Y así sucesivamente hasta el objeto `document`. - -![](event-order-bubbling.svg) - -Así si hacemos clic en `

`, entonces veremos 3 alertas: `p` -> `div` -> `form`. - -Este proceso se conoce como "propagación" porqué los eventos "se propagan" desde el elemento más al interior, a través de los padres, como una burbujas en el agua. - -```warn header="*Casi* todos los elementos se propagan." -La palabra clave en esta frase es "casi". - - -Por ejemplo, un evento `focus` no se propaga. Hay otros ejemplos también, los veremos. Pero aún así, esta es la excepción a la regla, la mayoría de eventos sí se propagan. -``` - -## event.target - -Un manejador en un elemento padre siempre puede obtener los detalles sobre dónde realmente ocurrió el evento. - -**El elemento anidado más profundo que causó el evento es llamado elemento *objetivo*, accesible como `event.target`** - -Nota la diferencia de `this` (=`event.currentTarget`): - -- `event.target` -- es el elemento "objetivo" que inició el evento, no cambia a través de todo el proceso de propagación. -- `this` -- es el elemento "actual", el que tiene un manejador ejecutándose en el momento. - -Por ejemplo, si tenemos un solo manejador `form.onclick`, este puede `atrapar` todos los clicks dentro del formulario. No importa dónde el clic se hizo, se propaga hasta el `` y ejecuta el manejador. - -En el manejador `form.onclick`: - -- `this` (=`event.currentTarget`) es el elemento ``, porque el manejador se ejecutó en él. -- `event.target` es el elemento actual dentro de el formulario al que se le hizo clic. - -Mira esto: - -[codetabs height=220 src="bubble-target"] - -Es posible que `event.target` sea igual a `this` -- ocurre cuando el clic se hace directamente en el elemento ``. - -## Detener la propagación - -Una propagación de evento empieza desde el elemento objetivo hacia arriba. Normalmente este continua hasta `` y luego hacia el objeto `document`, algunos eventos incluso alcanzan `window`, llamando a todos los manejadores en el camino. - -Pero cualquier manejador podría decidir que el evento se ha procesado por completo y detener su propagación. - -El método para esto es `event.stopPropagation()`. - -Por ejemplo, aquí `body.onclick` no funciona si haces clic en ` - -``` - -```smart header="event.stopImmediatePropagation()" -Si un elemento tiene multiples manejadores para un solo evento, aunque uno de ellos detenga la propagación, los demás aún se ejecutarán. - -En otras palabras, `event.stopPropagation()` detiene la propagación hacia arriba, pero todos los manejadores en el elemento actual se ejecutarán. - -Para detener la propagación y prevenir que los manejadores de el elemento actual se ejecuten, hay un método `event.stopImmediatePropagation()`. Después de él, ningún otro manejador será ejecutado. -``` - -```warn header="¡No detengas la propagación sino es necesario!" -La propagación es conveniente. No la detengas sin una necesidad real, obvia y arquitectónicamente bien pensada. - -A veces `event.stopPropagation()` crea trampas ocultas que luego se convierten en problemas. - -Por ejemplo: - -1. Creamos un menú anidado. Cada submenú maneja los clics en sus elementos y ejecuta `stopPropagation` para que el menu de arriba no se desencadene. -2. Luego decidimos atrapar los clic en toda la ventana, para seguir el rastro del comportamiento del usuario (dónde hacen clic). Algunos sistemas de análisis hacen eso. Usualmente el código usa `document.addEventListener('click'…)` para atrapar todos los clics. -3. Nuestro análisis no funcionará sobre el área dónde los clics son detenidos por `stopPropagation`. Tristemente, tenemos una "zona muerta". - -Usualmente no hay una necesidad real para prevenir la propagación. Una tarea que aparentemente requiere que sea resuelto por otros medios. Uno de ellas es usar eventos personalizados, cubriremos eso más tarde. También podemos escribir nuestros datos en el objeto `event` en un manejador y leerlo en otro, para así poder pasar información sobre el proceso de abajo a los manejadores en los padres. -``` - -## Captura - -Hay otra fase en el procesamiento de eventos llamada "captura". Es raro usarla en código real, pero a veces puede ser útil. - -El estándar de [eventos del DOM](http://www.w3.org/TR/DOM-Level-3-Events/) describe 3 fases de la propagación de eventos: - -1. Fase de captura -- el evento desciende al elemento. -2. Fase de objetivo -- el evento alcanza al elemento. -3. Fase de propagación -- el evento se propaga hacia arriba del elemento. - -Aquí está la imagen de un clic en `` dentro de una tabla, tomada desde la específicación: - -![](eventflow.svg) - -Se explica así: por un clic en `` el evento va primero a través de la cadena de ancestros hacia el elemento (fase de captura), luego alcanza el objetivo y se desendena ahí (fase de objetivo), y por último va hacia arriba (fase de propagación), ejecutando los manejadores en su camino. - -**Antes solo hablamos de la propagación porque la fase de captura es raramente usada. Normalmente es invisible a nosotros.** - -Los manejadores agregados usando `on`-propiedad ó usando atributos HTML ó `addEventListener(event, handler)` con dos argumentos no ejecutarán la fase de captura, únicamente ejecutarán la 2da y 3ra fase. - -Para atrapar un evento en la fase de captura, necesitamos preparar la opción `capture` como `true` en el manejador: - -```js -elem.addEventListener(..., {capture: true}) -// o, solo "true" es una forma más corta de {capture: true} -elem.addEventListener(..., true) -``` - -Hay dos posibles valores para la opción `capture`: - -- Si es `false` (por defecto), entonces el manejador es preparado para la fase de propagación. -- Si es `true`, entonces el manejador es preparado para la fase de captura. - -Es de notar que mientras formalmente hay 3 fases, la 2da fase ("la fase de objetivo": el evento alcanzó el elemento) no es manejada de forma separada; los manejadores en ambas fases, la de captura y propagación, se disparan en esa fase. - -Veamos ambas fases, captura y propagación, en acción: - -```html run autorun height=140 edit - - -FORM -

DIV -

P

-
-
- - -``` - -El código prepara manejadores de clic en *cada* elemento en el documento para ver cuáles están funcionando. - -Si haces clic en `

`, verás que la secuencia es: - -1. `HTML` -> `BODY` -> `FORM` -> `DIV` (fase de captura, el primer detector): -2. `P` (fase de objetivo, se dispara dos veces, tan pronto como preparemos los dos detectores: de captura y propagación) -3. `DIV` -> `FORM` -> `BODY` -> `HTML` (fase de propagación, el segundo detector). - -Hay un propiedad `event.eventPhase` que nos dice el número de fase en la qué el evento fue capturado. Pero es raramente usada, ya que usualmente lo sabemos en el manejador. - -```smart header="Para quitar el manejador, `removeEventListener` necesita la misma fase" -Si nosotros `addEventListener(..., true)`, entonces deberíamos mencionar la misma fase en `removeEventListener(..., true)` para remover el manejador correctamente. -``` - -````smart header="Detectores de eventos en el mismo elemento y en la misma fase se ejecutan en el orden de asignación" -Si tenemos multiples manejadores de eventos en la misma fase, asignados al mismo elemento con `addEventListener`, se ejecutarán en el orden que fueron creados: - -```js -elem.addEventListener("click", e => alert(1)); // garantizado que se ejecutara primero -elem.addEventListener("click", e => alert(2)); -``` -```` - -## Resumen - -Cuando un evento ocurre -- el más anidado elemento dónde ocurrió se reconoce como el "elemento objetivo" (`event.target`). - -- Luego el evento se mueve hacia abajo desde el documento raíz hacia `event.target`, llamando a los manejadores en el camino asignados con `addEventListener(..., true)` (`true` es una abreviación para `{captura: true}`). -- Luego los manejadores son llamados en el elemento objetivo mismo. -- Luego el evento se propaga hacia arriba desde `event.target` hacia la raíz, llamando a los manejadores que se asignaron usando `on` and `addEventListener` sin el 3er argumento o con el 3er argumento `false/{capture:false}`. - -Cada manejador puede acceder a las propiedades del objeto `event`: - -- `event.target` -- el elemento más profundo que originó el evento. -- `event.currentTarget` (=`this`) -- el elemento actual que maneja el evento (el qué tiene al manejador en él) -- `event.eventPhase` -- la fase actual (captura=1, objetivo=2, propagación=3). - -Cualquier manejador de evento puede detener el evento al llamar `event.stopPropagation()`, pero no es recomendado porque no podemos realmente asegurar que no lo necesitaremos más adelante, quizá para completar diferentes cosas. - -La fase de captura raramente es usada, usualmente manejamos los evento en propagación. Y hay una lógica atrás de eso. - -En el mundo real, cuando un accidente ocurre, las autoridades locales reaccionan primero. Ellos conocen mejor el área dónde ocurrió. Luego, si es necesario, autoridades de alto nível. - -Lo mismo para los manejadores de eventos. El código que se prepara en el manejador de un elemento en particular conoce el máximo de detalles sobre el elemento y qué hace. Un manejador en un `` particular puede ser adecuado para ese exacto ``, conocer todo sobre él, entonces debe tener su oportunidad primero. Lueog su padre inmediato también conoce sobre el contexto, pero un poco menos, y así sucesivamente hasta el elemento de arriba que maneja conceptos generales y se ejecuta al final. - -La propagación y captura ponen los cimientos para "delegación de eventos" -- un extremadamente poderoso patrón de manejo de eventos que se estudia en el siguiente capítulo. \ No newline at end of file diff --git a/2-ui/2-events/02-bubbling-and-capturing/article.md b/2-ui/2-events/02-bubbling-and-capturing/article.md index ac0186f42..33b180a37 100644 --- a/2-ui/2-events/02-bubbling-and-capturing/article.md +++ b/2-ui/2-events/02-bubbling-and-capturing/article.md @@ -1,24 +1,24 @@ -# Bubbling and capturing +# Propagación y captura -Let's start with an example. +Vamos a empezar con un ejemplo. -This handler is assigned to `

`, but also runs if you click any nested tag like `` or ``: +Este manejador está asignado a `
`, pero también se ejecuta si haces clic a cualquier elemento anidado como `` ó ``: ```html autorun height=60 -
- If you click on EM, the handler on DIV runs. +
+ Si haces clic enEM, el manejador en DIV es ejecutado.
``` -Isn't it a bit strange? Why does the handler on `
` run if the actual click was on ``? +¿No es un poco extraño? ¿Por qué el manejador en `
` es ejecutado, si el clic fue hecho en ``? -## Bubbling +# Propagación -The bubbling principle is simple. +El principio de propagación es simple. -**When an event happens on an element, it first runs the handlers on it, then on its parent, then all the way up on other ancestors.** +**Cuando un evento ocurre en un elemento, este primero ejecuta los manejadores que tiene asignados, luego los manejadores de su padre, y así hasta otros ancentros.** -Let's say we have 3 nested elements `FORM > DIV > P` with a handler on each of them: +Dígamos que tenemos 3 elementos anidados `FORM > DIV > P` con un manejador en cada uno de ellos: ```html run autorun