Eventos de Componente
Esta página asume que ya has leído los Fundamentos de Componentes. Léela primero si eres nuevo en los componentes.
Emitir y Escuchar Eventos
Un componente puede emitir eventos personalizados directamente en expresiones de template (por ejemplo, en un handler de v-on) usando el método $emit incorporado:
template
<!-- MyComponent -->
<button @click="$emit('someEvent')">Haz clic</button>El componente padre puede entonces escucharlo usando v-on:
template
<MyComponent @some-event="callback" />El modificador .once también es compatible con los listeners de eventos de componente:
template
<MyComponent @some-event.once="callback" />Al igual que los componentes y los props, los nombres de eventos proporcionan una transformación de mayúsculas y minúsculas automática. Observa que emitimos un evento en camelCase, pero podemos escucharlo usando un listener en kebab-cased en el padre. Al igual que con el uso de mayúsculas/minúsculas en props, recomendamos usar listeners de eventos en kebab-cased en los templates.
TIP
A diferencia de los eventos nativos del DOM, los eventos emitidos por componentes no hacen bubbling. Solo puedes escuchar los eventos emitidos por un componente hijo directo. Si necesitas comunicar entre componentes hermanos o profundamente anidados, utiliza un bus de eventos externo o una solución de gestión de estado global.
Argumentos de Evento
A veces es útil emitir un valor específico con un evento. Por ejemplo, es posible que deseemos que el componente <BlogPost> sea el encargado de cuánto debe agrandar el texto. En esos casos, podemos pasar argumentos adicionales a $emit para proporcionar este valor:
template
<button @click="$emit('increaseBy', 1)">
Aumentar en 1
</button>Luego, cuando escuchamos el evento en el componente padre, podemos usar una función de flecha en línea como listener, lo que nos permite acceder al argumento del evento:
template
<MyButton @increase-by="(n) => count += n" />O, si el handler del evento es un método:
template
<MyButton @increase-by="increaseCount" />Entonces el valor se pasará como el primer parámetro de ese método:
js
function increaseCount(n) {
count.value += n
}TIP
Todos los argumentos adicionales pasados a $emit() después del nombre del evento se reenviarán al listener. Por ejemplo, con $emit('foo', 1, 2, 3), la función listener recibirá tres argumentos.
Declarar Eventos Emitidos
Un componente puede declarar explícitamente los eventos que emitirá usando la macro defineEmits():
vue
<script setup>
defineEmits(['inFocus', 'submit'])
</script>El método $emit que usamos en la <template> no es accesible dentro de la sección <script setup> de un componente, pero defineEmits() devuelve una función equivalente que podemos usar en su lugar:
vue
<script setup>
const emit = defineEmits(['inFocus', 'submit'])
function buttonClick() {
emit('submit')
}
</script>La macro defineEmits() no puede usarse dentro de una función, debe colocarse directamente dentro de <script setup>, como en el ejemplo anterior.
Si estás utilizando una función setup explícita en lugar de <script setup>, los eventos deben declararse usando la opción emits, y la función emit se expone 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 de setup(), emit se puede desestructurar de forma segura:
js
export default {
emits: ['inFocus', 'submit'],
setup(props, { emit }) {
emit('submit')
}
}La opción emits y la macro defineEmits() también admiten una sintaxis de objeto. Si usas TypeScript, puedes tipar los argumentos, lo que nos permite realizar la validación en tiempo de ejecución de la carga útil de los eventos emitidos:
vue
<script setup lang="ts">
const emit = defineEmits({
submit(payload: { email: string; password: string }) {
// devuelve `true` o `false` para indicar
// si la validación pasó / falló
}
})
</script>Si estás utilizando 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: Tipado de Emits de Componentes
Aunque es opcional, se recomienda definir todos los eventos emitidos para documentar mejor cómo debe funcionar un componente. También permite a Vue excluir listeners conocidos de los atributos de fallthrough, evitando casos extremos causados por eventos del DOM enviados manualmente por código de terceros.
TIP
Si un evento nativo (por ejemplo, click) se define en la opción emits, el listener ahora solo escuchará los eventos click emitidos por el componente y ya no responderá a los eventos click nativos.
Validación de Eventos
Similar a la validación de tipo de prop, un evento emitido puede validarse si se define con la sintaxis de objeto en lugar de la sintaxis de array.
Para agregar validación, al evento se le asigna una función que recibe los argumentos pasados a la llamada 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 evento submit
submit: ({ email, password }) => {
if (email && password) {
return true
} else {
console.warn('¡Carga útil de evento submit no válida!')
return false
}
}
})
function submitForm(email, password) {
emit('submit', { email, password })
}
</script>