[ Web Proxy ]
URL:
Viewing: https://es.javascript.info/dispatch-events [Back]  [Original]

Envo de eventos personalizados
ES

Queremos que este proyecto de cdigo abierto est disponible para personas de todo el mundo.

Ayuda a traducir el contenido de este tutorial a tu idioma!

    Buscar en Javascript.info:
    Buscar en el tutorial:
    Light themeDark theme
    DanskEnglishEspaolFranaisIndonesiaItalianoTrkeOzbek

    No solo podemos asignar controladores, sino tambin generar eventos desde JavaScript.

    Los eventos personalizados se pueden utilizar para crear componentes grficos. Por ejemplo, un elemento raz de nuestro propio men basado en JS puede desencadenar eventos que indiquen lo que sucede con el men: abrir (men abierto),seleccionar (se selecciona un elemento) y as sucesivamente. Otro cdigo puede escuchar los eventos y observar lo que sucede con el men.

    No solo podemos generar eventos completamente nuevos, que inventamos para nuestros propios fines, sino tambin eventos integrados, como click, mousedown, etc. Eso puede ser til para las pruebas automatizadas.

    Constructor de eventos

    Las clases de eventos integradas forman una jerarqua, similar a las clases de elementos DOM. La raz es la clase incorporada Event.

    Podemos crear objetos Event as:

    let event = new Event(type[, options]);

    Argumentos:

    • type tipo de event, un string como "click" o nuestro propio evento como "mi-evento".

    • options el objeto con 2 propiedades opcionales:

      • bubbles: true/false si es true, entonces el evento se propaga.
      • cancelable: true/false si es true, entonces la accin predeterminada puede ser prevenida. Ms adelante veremos qu significa para los eventos personalizados.

      Por defecto, los dos son false: {bubbles: false, cancelable: false}.

    dispatchEvent

    Despus de que se crea un objeto de evento, debemos ejecutarlo en un elemento usando la llamada elem.dispatchEvent(event).

    Luego, los controladores reaccionan como si fuera un evento normal del navegador. Si el evento fue creado con la bandera bubbles, entonces se propaga.

    En el siguiente ejemplo, el evento click se inicia en JavaScript. El controlador funciona de la misma manera que si se hiciera clic en el botn:

    <button id="elem" onclick="alert('Clic!');">Click automtico</button>
    
    <script>
      let event = new Event("click");
      elem.dispatchEvent(event);
    </script>
    event.isTrusted

    Hay una forma de diferenciar un evento de usuario real de uno generado por script.

    La propiedad event.isTrusted es true para eventos que provienen de acciones de usuarios reales y false para eventos generados por script.

    Ejemplo de Bubbling

    Podemos crear un evento bubbling con el nombre "hello" y capturarlo en document.

    Todo lo que necesitamos es establecer bubbles en true:

    <h1 id="elem">Hola desde el script!</h1>
    
    <script>
      // Captura en document...
      document.addEventListener("hello", function(event) { // (1)
        alert("Hola desde " + event.target.tagName); // Hola desde H1
      });
    
      // ...Envo en elem!
      let event = new Event("hello", {bubbles: true}); // (2)
      elem.dispatchEvent(event);
    
    // el controlador del documento se activar y mostrar el mensaje.
    
    </script>

    Notas:

    1. Debemos usar addEventListener para nuestros eventos personalizados, porque on<event> solo existe para eventos incorporados, document.onhello no funciona.
    2. Debes poner bubbles:true, de otra manera el evento no se propagar.

    La mecnica de bubbling es la misma para los eventos integrados (click) y personalizados (hello). Tambin hay etapas de captura y propagacin.

    MouseEvent, KeyboardEvent y otros

    Aqu hay una breve lista de clases para eventos UI (interfaz de usuario) de la especificacin de eventos UI:

    • UIEvent
    • FocusEvent
    • MouseEvent
    • WheelEvent
    • KeyboardEvent

    Deberamos usarlos en lugar de new Event si queremos crear tales eventos. Por ejemplo, new MouseEvent("click").

    El constructor correcto permite especificar propiedades estndar para ese tipo de evento.

    Como clientX/clientY para un evento de mouse:

    let event = new MouseEvent("click", {
      bubbles: true,
      cancelable: true,
      clientX: 100,
      clientY: 100
    });
    
    alert(event.clientX); // 100

    Tenga en cuenta: el constructor genrico Event no lo permite.

    Intentemos:

    let event = new Event("click", {
      bubbles: true, // solo bubbles y cancelable
      cancelable: true, // funcionan en el constructor de Event
      clientX: 100,
      clientY: 100
    });
    
    alert(event.clientX); // undefined, se ignora la propiedad desconocida!

    Tcnicamente, podemos solucionarlo asignando directamente event.clientX=100 despus de la creacin. Entonces eso es una cuestin de conveniencia y de seguir las reglas. Los eventos generados por el navegador siempre tienen el tipo correcto.

    La lista completa de propiedades para diferentes eventos de UI se encuentra en la especificacin, por ejemplo, MouseEvent.

    Eventos personalizados

    Para nuestros tipos de eventos completamente nuevos, como "hello", deberamos usar new CustomEvent. Tcnicamente, CustomEvent es lo mismo que Event, con una excepcin.

    En el segundo argumento (objeto) podemos agregar una propiedad adicional detail para cualquier informacin personalizada que queramos pasar con el evento.

    Por ejemplo:

    <h1 id="elem">Hola para John!</h1>
    
    <script>
      // detalles adicionales que vienen con el evento para el controlador.
      elem.addEventListener("hello", function(event) {
        alert(event.detail.name);
      });
    
      elem.dispatchEvent(new CustomEvent("hello", {
        detail: { name: "John" }
      }));
    </script>

    La propiedad detail puede tener cualquier dato. Tcnicamente podramos vivir sin l, porque podemos asignar cualquier propiedad a un objeto new Event regular despus de su creacin. Pero CustomEvent proporciona el campo especial detail para evitar conflictos con otras propiedades del evento.

    Adems, la clase de evento describe qu tipo de evento es, y si el evento es personalizado, entonces deberamos usar CustomEvent solo para tener claro qu es.

    event.preventDefault()

    Muchos eventos del navegador tienen una accin predeterminada, como ir a un enlace, iniciar una seleccin, etc.

    Para eventos nuevos y personalizados, definitivamente no hay acciones predeterminadas del navegador, pero un cdigo que distribuye dicho evento puede tener sus propios planes de qu hacer despus de activar el evento.

    Al llamar a event.preventDefault(), un controlador de eventos puede enviar una seal de que esas acciones deben cancelarse.

    En ese caso, la llamada a elem.dispatchEvent(event) devuelve false. Y el cdigo que lo envi sabe que no debera continuar.

    Veamos un ejemplo prctico: un conejo escondido (podra ser un men de cierre u otra cosa).

    A continuacin puede ver una funcin #rabbit y hide() que distribuye el evento "hide" en l, para que todas las partes interesadas sepan que el conejo se va a esconder.

    Cualquier controlador puede escuchar ese evento con rabbit.addEventListener('hide', ...) y, si es necesario, cancelar la accin usando event.preventDefault(). Entonces el conejo no desaparecer:

    <pre id="rabbit">
      |\   /|
       \|_|/
       /. .\
      =\_Y_/=
       {>o<}
    </pre>
    <button onclick="hide()">Esconder()</button>
    
    <script>
      // hide() ser llamado automticamente en 2 segundos.
      function hide() {
        let event = new CustomEvent("hide", {
          cancelable: true // sin esa bandera preventDefault no funciona
        });
        if (!rabbit.dispatchEvent(event)) {
          alert('La accin fue impedida por un controlador');
        } else {
          rabbit.hidden = true;
        }
      }
    
      rabbit.addEventListener('hide', function(event) {
        if (confirm("Llamar a preventDefault?")) {
          event.preventDefault();
        }
      });
    </script>

    Tenga en cuenta: el evento debe tener la bandera cancelable: true, de lo contrario, la llamada event.preventDefault() se ignora.

    Los eventos dentro de eventos son sincrnicos

    Usualmente los eventos se procesan en una cola. Por ejemplo: si el navegador est procesando onclick y ocurre un nuevo evento porque el mouse se movi, entonces el manejo de este ltimo se pone en cola, y el controlador correspondiente mousemove ser llamado cuando el procesamiento de onclick haya terminado.

    La excepcin notable es cuando un evento se inicia desde dentro de otro, por ejemplo, usando dispatchEvent. Dichos eventos se procesan inmediatamente: se llaman los nuevos controladores de eventos y luego se reanuda el manejo de eventos actual.

    Por ejemplo, en el cdigo siguiente, el evento menu-open se activa durante el onclick.

    Se procesa inmediatamente, sin esperar a que termine el controlador onclick:

    <button id="menu">Menu (dame clic)</button>
    
    <script>
      menu.onclick = function() {
        alert(1);
    
        menu.dispatchEvent(new CustomEvent("menu-open", {
          bubbles: true
        }));
    
        alert(2);
      };
    
      // se dispara entre 1 y 2
      document.addEventListener('menu-open', () => alert('anidado'));
    </script>

    El orden de salida es: 1 anidado 2.

    Tenga en cuenta que el evento anidado menu-open se captura en document. La propagacin y el manejo del evento anidado finaliza antes de que el procesamiento vuelva al cdigo externo (onclick).

    No se trata solo de dispatchEvent, hay otros casos. Si un controlador de eventos llama a mtodos que desencadenan otros eventos, tambin se procesan sincrnicamente, de forma anidada.

    Supongamos que no nos gusta. Querramos que onclick se procesara por completo primero, independientemente de menu-open o cualquier otro evento anidado.

    Entonces podemos poner el dispatchEvent (u otra llamada de activacin de eventos) al final de onclick o, mejor an, envolverlo en el setTimeout de retardo cero:

    <button id="menu">Menu (dame clic)</button>
    
    <script>
      menu.onclick = function() {
        alert(1);
    
        setTimeout(() => menu.dispatchEvent(new CustomEvent("menu-open", {
          bubbles: true
        })));
    
        alert(2);
      };
    
      document.addEventListener('menu-open', () => alert('anidado'));
    </script>

    Ahora dispatchEvent se ejecuta asincrnicamente despus de que la ejecucin del cdigo actual finaliza, incluyendo menu.onclick. Los controladores de eventos estn totalmente separados.

    El orden de salida se convierte en: 1 2 anidado.

    Resumen

    Para generar un evento a partir del cdigo, primero necesitamos crear un objeto de evento.

    El constructor genrico Event(name, options) acepta un nombre de evento arbitrario y el objeto options con dos propiedades:

    • bubbles: true si el evento debe propagarse.
    • cancelable: true si event.preventDefault() debe funcionar.

    Otros constructores de eventos nativos como MouseEvent, KeyboardEvent, y similares, aceptan propiedades especficas para ese tipo de evento. Por ejemplo, clientX para eventos de mouse.

    Para eventos personalizados deberamos usar el constructor CustomEvent. Este tiene una opcin adicional llamada detail a la que podemos asignarle los datos especficos del evento. De esta forma, todos los controladores pueden accederlos como event.detail.

    A pesar de la posibilidad tcnica de generar eventos del navegador como click o keydown, debemos usarlo con mucho cuidado.

    No deberamos generar eventos de navegador, ya que es una forma trillada de ejecutar controladores. Esa es una mala arquitectura la mayor parte del tiempo.

    Se pueden generar eventos nativos:

    • Como un truco sucio para hacer que las bibliotecas de terceros funcionen de la manera necesaria, si es que ellas no proporcionan otros medios de interaccin.
    • Para pruebas automatizadas, que el script haga clic en el botn y vea si la interfaz reacciona correctamente.

    Los eventos personalizados con nuestros propios nombres a menudo se generan con fines arquitectnicos, para sealar lo que sucede dentro de nuestros mens, controles deslizantes, carruseles, etc.

    Mapa del Tutorial

    Comentarios

    lea esto antes de comentar
    • Si tiene sugerencias sobre qu mejorar, por favor enviar una propuesta de GitHub o una solicitud de extraccin en lugar de comentar.
    • Si no puede entender algo en el artculo, por favor explique.
    • Para insertar algunas palabras de cdigo, use la etiqueta <code>, para varias lneas envolverlas en la etiqueta <pre>, para ms de 10 lneas utilice una entorno controlado (sandbox) (plnkr, jsbin, codepen)

    Web Proxy Viewer  |  New URL  |  Original Page