En la edición anterior de esta serie, vimos qué son los eventos y los props en Vue, y fuimos descubriendo cómo usarlos. En este capítulo, nos vamos a centrar en los eventos del DOM de toda la vida y en cómo Vue los integra a sus directivas, así como en la creación y el manejo de eventos personalizados.

Tipos de eventos

A la hora de manejar eventos en Vue, lo primero que tenemos que discernir es si estamos hablando de un evento del DOM (clickscrollfocus, etc.) o un evento personalizado. La manera de manejarlo va a diferir según el caso.

Eventos del DOM

A la hora de manejar eventos del DOM, lo primero que vamos a hacer es usar en el template la directiva v-on. Por ejemplo, para mostrar un alert al hacer click en un botón, podríamos tener un template como el siguiente:

<template> 
    <button v-on:click="alert('Me hiciste click')">Haceme click</button> 
</template> 

Claro que también podemos pasar el nombre de un método del componente:

<template> 
    <button v-on:click="mostrarAlerta">Haceme click</button> 
</template> 

<script> 
    methods: { 
        mostrarAlerta: function () { 
            alert("Me hiciste click"); 
        } 
    } 
</script> 

Manipulación de los eventos del DOM

Es muy común en este tipo de eventos querer recurrir a los métodos preventDefault() o stopPropagation() del objeto event que se genera cuando se disparan eventos del DOM. Para hacerlo, tenemos que tener en cuenta que la directiva v-on proporciona el objeto $event, que podemos usar de manera inline o como parámetro de nuestro método personalizado. Para los ejemplos anteriores, podríamos hacer algo como lo siguiente:

Inline

<template> 
    <button
        v-on:click="$event.preventDefault(); alert('Me hiciste click')">
            Haceme click
    </button> 
</template> 

Con método

<template> 
    <button v-on:click="mostrarAlerta($event)">Haceme click</button> 
</template> 

<script> 
    methods: { 
        mostrarAlerta: function (event) { 
            event.preventDefault(); 
            alert("Me hiciste click"); 
        } 
    } 
</script> 

Modificadores de eventos del DOM

De manera alternativa al uso del objeto $event, Vue proporciona modificadores para los eventos en forma de sufijos separados del nombre del evento por un punto. Los sufijos disponibles son:

  • .stop
  • .prevent
  • .capture
  • .self
  • .once
  • .passive


Repliquemos el ejemplo anterior con el uso de estos modificadores:

<template> 
    <button v-on:click.prevent="mostrarAlerta">Haceme click</button> 
</template> 

<script> 
    methods: { 
        mostrarAlerta: function () { 
            alert("Me hiciste click"); 
        } 
    } 
</script> 

 Los modificadores también se pueden encadenar. Por ejemplo, para evitar la recarga de la página solo cuando se hace click en el componente propiamente dicho, haríamos:

<template> 
    <button v-on:click.self.prevent="mostrarAlerta">Haceme click</button> 
</template> 

Por último, es importante tener en cuenta que el orden de estos sufijos cambia el comportamiento. Si invertimos los modificadores del ejemplo anterior (v-on:click.prevent.self en lugar de v-on:click.self.prevent), el prevent tendría efecto sobre todos los clicks y no solo los clicks que satisfagan primero la condición del self.

Modificadores para eventos con teclas

En el caso de los eventos relacionados a la pulsación de teclas del teclado (keyup, keydown, etc.), contamos con modificadores que nos permiten indicar teclas específicas para activar el evento. Por ejemplo, si queremos que un input dispare una acción al apretar la tecla Enter cuando estamos con el cursor en él, podríamos hacer algo como:

<template> 
    <input v-on:keydown.enter="realizarAccion"></button> 
</template> 

Para una lista más exhaustiva de estos eventos y sus modificadores, los referimos a la documentación de Vue.

Eventos personalizados

Un aspecto importante del manejo de eventos del DOM en Vue es que solo podemos vincular esos eventos con métodos que están dentro del mismo componente. No obstante, si empezamos a programar la interfaz de un sitio en Vue, pronto nos vamos a encontrar con la necesidad de hacer que los componentes se comuniquen entre ellos. Examinemos el siguiente ejemplo:

 

 

En el paso 2 del ejemplo, el componente B, tiene un botón Actualizar, cuyo evento v-on:click seguramente dispare un método dentro del mismo componente B. Sin embargo, en este caso necesitamos que el componente B le comunique al componente A que es necesario actualizar la lista de usuarios. Para lograr esto, necesitamos usar un evento personalizado.

Emisión de eventos

El primer paso para comunicar componentes mediante eventos es que un componente emita un evento. En nuestro caso, el evento v-on:click del botón Actualizar del componente B debería disparar un método como el siguiente:

<template> 
    <button v-on:click="solicitarListaActualizada">Actualizar</button> 
</template> 

<script> 
    props: { 
        listaDeUsuarios: [] 
    }, 
    methods: { 
        solicitarListaActualizada: function () { 
            this.$emit("evento-solicitar-lista-actualizada"); 
        } 
    } 
</script> 

Como podemos ver, dentro del método solicitarListaActualizada hacemos uso del método $emit que contienen todos los componentes de Vue. Este método va a emitir un evento con el nombre que pasemos como parámetro hacia el componente padre del componente actual.

Recepción de eventos

El siguiente paso sería hacer que el componente padre, en este caso el componente A, escuche ese evento y lo asocie a un método propio. Ejemplo:

<template> 
    <componente-b 
        v-bind:lista-de-usuarios="listaDeUsuarios" 
        v-on:evento-solicitar-lista-actualizada="actualizarLista"> 
    </componente-b> 
</template> 

<script> 
    data: { 
        listaDeUsuarios: [] 
    }, 
    methods: { 
        actualizarLista: function () { 
            ... 
        } 
    } 
</script> 

Como podemos ver, al momento de inicializar el componente B, no solo vinculamos la variable listaDeUsuarios con su prop equivalente, sino que vinculamos el evento que emite el componente B con un método propio del componente A. El método actualizarLista ahora debería solicitar la lista al backend y asignar la respuesta a la variable listaDeUsuarios, de modo que por reactividad se actualice automáticamente la lista del componente B.

Eventos que transmiten datos

Otro aspecto importante de los eventos personalizados es que podemos usarlos para transmitir datos de un componente a otro. Siguiendo con el ejemplo anterior, puede que cuando el usuario hace clic en un ícono de información de la lista de usuarios, queramos solicitar al backend la información detallada de ese usuario. El diseño que debemos seguir es el mismo, solo que esta vez debemos informarle al componente A el id del usuario cuya información queremos conseguir. Esto lo podemos hacer enviándole ese dato en el evento mediante el uso del segundo parámetro de la función $emit:

methods: { 
    ... 
    solicitarInformacionUsuario: function (id) { 
        this.$emit("evento-solicitar-info-usuario", id); 
    } 
} 

Y para recibirlo en el componente A:

<template> 
    <componente-b 
        v-bind:lista-de-usuarios="listaDeUsuarios"
        v-on:evento-solicitar-lista-actualizada="actualizarLista"
        v-on:evento-solicitar-info-usuario="obtenerInfoUsuario"> 
    </componente-b> 
</template> 

<script> 
    data: { 
        listaDeUsuarios: [] 
    }, 
    methods: { 
        actualizarLista: function () { 
            ... 
        }, 
        obtenerInfoUsuario: function (id) { 
            ... 
        } 
    } 
</script> 

Conclusión

En este artículo vimos algunas maneras de manipular los eventos del DOM en Vue, así como las directivas y modificadores que nos proporciona esta librería para facilitar su manejo. También aprendimos a emitir y recibir eventos personalizados, ya sea con o sin datos incluidos. En el próximo artículo, vamos a analizar los eventos de los hooks del ciclo de vida de Vue y vamos a ver un patrón de diseño para crear nuestro propio bus de eventos. ¡Hasta la próxima! 

Mandanos tus sugerencias

Ayudanos con ideas para los artículos de este blog a contacto@somospnt.com

¡Seguínos en nuestras redes sociales para enterarte de los últimos posts!