vuejs-emit-eventos-componentes

Comunicación entre componentes en Vue.js con emit

  • 3 min

En Vue.js, emit es una función que permite a un componente hijo enviar un evento personalizado a su componente padre.

vue-events

Mientras que los props son la forma más común de pasar datos de un componentes padre a un hijo, los eventos son la forma más común de comunicación en sentido inverso.

  • Props: Permiten el flujo de datos descendente (de padre a hijo)
  • Eventos: Permiten el flujo de datos ascendente (de hijo a padre)

Además, el evento emitido puede llevar datos asociados, lo que permite al padre reaccionar y realizar acciones basadas en lo que ocurre en el hijo.

Este patrón de diseño permite un flujo de datos unidireccional y es común en muchos frameworks modernos Vue.js.

Cómo usar emit

En Vue.js podemos declarar los eventos que un componente puede emitir de varias maneras. La más común es utilizando la función defineEmits():

<script setup>
// Definimos los eventos que este componente puede emitir
const emit = defineEmits(['actualizar', 'eliminar', 'seleccionar'])

// Ahora podemos usar la función emit en nuestro componente
function handleClick() {
  emit('actualizar', { id: 1, valor: 'nuevo valor' })
}
</script>
  • defineEmits: Es una función que nos permite declarar los eventos que el componente puede emitir.
  • emit: Es una función que recibe dos argumentos:
    1. El nombre del evento (como una cadena de texto)
    2. Los datos que queremos enviar al componente padre (opcional)

La función defineEmits nos devuelve una función emit configurada con los eventos que queramos, que luego podemos usar en nuestro código.

Ejemplo de emit

Vamos a verlo mejor si hacemos un ejemplo sencillo.

  • Creamos un componente hijo que emite un evento cuando se hace clic en un botón.
  • El componente padre escuchará este evento y mostrará un mensaje en la consola.
<template>
  <button @click="handleClick">Haz clic</button>
</template>

<script setup>
const emit = defineEmits(['boton-clicado']);

const handleClick = () => {
  emit('boton-clicado', { mensaje: 'El botón fue clicado' });
};
</script>
  • handleClick: Es una función que se ejecuta cuando el usuario hace clic en el botón.
  • emit('boton-clicado', { mensaje: '...' }): Emite un evento llamado boton-clicado con un objeto que contiene un mensaje.
<template>
  <div>
    <ChildComponent @boton-clicado="manejarClic" />
  </div>
</template>

<script setup>
import ChildComponent from './ChildComponent.vue';

const manejarClic = (datos) => {
  console.log('Evento recibido:', datos.mensaje);
};
</script>
  • @boton-clicado="manejarClic": Escucha el evento boton-clicado emitido por el componente hijo y ejecuta la función manejarClic.
  • manejarClic: Recibe los datos enviados por el hijo y los muestra en la consola.

Validación de eventos con defineEmits

También podemos usar una sintaxis más detallada para validar el tipo de datos que se emiten:

<!-- HijoComponent.vue -->
<template>
  <button @click="handleClick">Haz clic</button>
</template>

<script setup>
const emit = defineEmits({
  // Validamos que el evento 'boton-clicado' reciba un objeto con un mensaje
  'boton-clicado': (payload) => {
    return payload.mensaje && typeof payload.mensaje === 'string';
  },
});

const handleClick = () => {
  emit('boton-clicado', { mensaje: 'El botón fue clicado' });
};
</script>
  • defineEmits: Define y valida los eventos que el componente puede emitir.
  • Validación: Asegura que el payload del evento cumpla con ciertas condiciones.

Comunicación Bidireccional con v-model y emit

Los eventos personalizados son la base de la directiva v-model en componentes personalizados.

Podemos implementar componentes que soporten v-model emitiendo el evento update:modelValue:

<template>
  <input :value="modelValue" @input="handleInput" />
</template>

<script setup>
defineProps({
  modelValue: {
    type: String,
    required: true,
  },
});

const emit = defineEmits(['update:modelValue']);

const handleInput = (event) => {
  emit('update:modelValue', event.target.value);
};
</script>
  • modelValue: Es el prop que recibe el valor actual.
  • emit('update:modelValue', ...): Emite un evento para actualizar el valor en el componente padre.
<template>
  <div>
    <CustomInput v-model="texto" />
    <p>Texto ingresado: {{ texto }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import InputPersonalizado from './InputPersonalizado.vue';

const texto = ref('');
</script>
  • v-model="texto": Enlaza el valor del input con la variable texto en el componente padre.

Internamente, v-model utiliza emit para notificar cambios al componente padre