Eventos de los Componentes
Esta página supone que ya has leído los Fundamentos de los Componentes. Léelo primero si eres nuevo en el tema de componentes.
Emitiendo y Escuchando Eventos
Un componente puede emitir eventos personalizados directamente en las expresiones de la plantilla (por ejemplo, en un manejador v-on
) utilizando el método incorporado $emit
:
template
<!-- MyComponent -->
<button @click="$emit('someEvent')">Hazme clic</button>
El padre puede entonces escucharlo usando v-on
:
template
<MyComponent @some-event="callback" />
El modificador .once
también es compatible con los escuchadores de eventos de los componentes:
template
<MyComponent @some-event.once="callback" />
Al igual que los componentes y props, los nombres de eventos proporcionan una transformación automática de mayúsculas y minúsculas. Observa que emitimos un evento camelCase, pero podemos escucharlo usando un listener kebab-cased en el padre. Como en el caso de la Nomenclatura de las Props, recomendamos utilizar escuchas de eventos con mayúsculas en las plantillas.
TIP
A diferencia de los eventos nativos del DOM, los eventos emitidos por los componentes no se reproducen. Sólo puedes escuchar los eventos emitidos por un componente hijo directo. Si es necesario comunicarse entre componentes hermanos o profundamente anidados, utiliza un bus de eventos externo o una solución de gestión de estado global.
Argumentos del Evento
A veces es útil emitir un valor específico con un evento. Por ejemplo, podemos querer que el componente <BlogPost>
se encargue de cuánto ampliar el texto. En esos casos, podemos pasar argumentos extra a $emit
para proporcionar este valor:
template
<button @click="$emit('increaseBy', 1)">
Aumentar en 1
</button>
Así, cuando escuchamos el evento en el padre, podemos utilizar una función de flecha en línea como oyente, lo que nos permite acceder al argumento del evento:
template
<MyButton @increase-by="(n) => count += n" />
O, si el manejador del evento es un método:
template
<MyButton @increase-by="increaseCount" />
Entonces el valor se pasará como primer parámetro de ese método:
js
function increaseCount(n) {
count.value += n
}
TIP
Todos los argumentos adicionales que se pasen a $emit()
después del nombre del evento serán reenviados a la función de escucha. Por ejemplo, con $emit('foo', 1, 2, 3)
la función de escucha recibirá tres argumentos.
Declarando Eventos Emitidos
Un componente puede declarar explícitamente los eventos que emitirá utilizando la macro defineEmits()
:
vue
<script setup>
defineEmits(['inFocus', 'submit'])
</script>
El método $emit
que utilizamos en la <plantilla>
no es accesible dentro de la sección <script setup>
de un componente, pero defineEmits()
devuelve una función equivalente que podemos utilizar en su lugar:
vue
<script setup>
const emit = defineEmits(['inFocus', 'submit'])
function buttonClick() {
emit('submit')
}
</script>
La macro defineEmits()
no puede ser usada dentro de una función; debe ser colocada directamente dentro de <script setup>
, como en el ejemplo anterior.
Si estás usando una función explícita setup
en lugar de <script setup>
, los eventos deben ser declarados usando la opción emits
, y la función emit
es expuesta en el contexto de setup()
:
js
export default {
emits: ['inFocus', 'submit'],
setup(props, ctx) {
ctx.emit('submit')
}
}
Al igual que con otras propiedades del contexto setup()
, emit
puede ser desestructurado con seguridad:
js
export default {
emits: ['inFocus', 'submit'],
setup(props, { emit }) {
emit('submit')
}
}
La opción emits
y el macro defineEmits()
también admiten una sintaxis de objeto. Si utilizas TypeScript puedes tipar argumentos, lo que nos permite realizar una validación en tiempo de ejecución del payload de los eventos emitidos:
vue
<script setup>
const emit = defineEmits({
submit(payload: { email: string; password: string }) {
// devuelve `true` o `false` para indicar
// que la validación ha pasado / no ha pasado
}
})
</script>
Si estás usando TypeScript con <script setup>
, también es posible declarar eventos emitidos usando anotaciones de tipo puro:
vue
<script setup lang="ts">
const emit = defineEmits<{
(e: 'change', id: number): void
(e: 'update', value: string): void
}>()
</script>
Más detalles: Escritura de Emits del Componente
Aunque es opcional, se recomienda definir todos los eventos emitidos para documentar mejor cómo debe funcionar un componente. Esto también permite a Vue excluir a los escuchadores conocidos desde los atributos fallthrough, evitando situaciones críticas causadas por eventos del DOM enviados manualmente por código de terceros.
TIP
Si se define un evento nativo (por ejemplo, clic
) en la opción emits
, el escuchador solo escuchará ahora los eventos clic
emitidos por el componente y ya no responderá a los eventos clic
nativos.
Validación de Eventos
De forma similar a la validación del tipo de props, un evento emitido puede ser validado si se define con la sintaxis de objeto en lugar de la sintaxis de array.
Para agregar la validación, se asigna al evento una función que recibe los argumentos pasados a la invocación de emit
y devuelve un booleano para indicar si el evento es válido o no.
vue
<script setup>
const emit = defineEmits({
// Sin validación
click: null,
// Validar el evento submit
submit: ({ email, password }) => {
if (email && password) {
return true
} else {
console.warn('¡Payload del evento submit inválido!')
return false
}
}
})
function submitForm(email, password) {
emit('submit', { email, password })
}
</script>