Как обрабатывать события от дочернего компонента?
Во Vue события от дочернего компонента обрабатываются с помощью механизма всплытия событий и метода $emit, который используется внутри дочернего компонента для отправки события наружу. Родительский компонент может "слушать" эти события и выполнять нужную логику. Этот подход позволяет дочернему компоненту быть более изолированным и переиспользуемым, а родителю — управлять поведением на основе действий дочернего компонента.
Основной механизм: $emit
Дочерний компонент с помощью метода this.$emit отправляет событие. Родитель "подписывается" на это событие при использовании компонента, указывая обработчик через директиву v-on или сокращённый синтаксис @.
Простой пример
Дочерний компонент: ChildComponent.vue
<template>
<button @click="handleClick">Нажми меня</button>
</template>
<script>
export default {
methods: {
handleClick() {
this.$emit('childClicked', 'Привет от дочернего компонента')
}
}
}
</script>
Родительский компонент: ParentComponent.vue
<template>
<div>
<ChildComponent @childClicked="onChildClicked" />
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue'
export default {
components: { ChildComponent },
methods: {
onChildClicked(message) {
console.log('Получено событие:', message)
}
}
}
</script>
В этом примере при клике на кнопку в дочернем компоненте генерируется событие childClicked, и родитель его ловит с помощью @childClicked.
Передача данных через событие
События можно вызывать с аргументами — любыми значениями: строками, числами, объектами, массивами и т.д. Эти значения будут переданы в обработчик события родителя.
this.$emit('saveData', { name: 'Alex', age: 32 })
Родитель:
<ChildComponent @saveData="handleSave" />
methods: {
handleSave(payload) {
console.log(payload.name) // Alex
}
}
Несколько аргументов
Можно передать несколько аргументов:
this.$emit('someEvent', arg1, arg2)
Родитель:
<ChildComponent @someEvent="(a, b) => doSomething(a, b)" />
Названия событий
Названия событий могут быть произвольными, но часто используют kebab-case, например:
this.$emit('item-selected')
Родитель:
<ChildComponent @item-selected="handleSelect" />
Или camelCase, но тогда лучше использовать v-on вместо @:
<ChildComponent v-on:itemSelected="handleSelect" />
Пример: форма и кнопка
Дочерний компонент SubmitButton.vue
<template>
<button @click="submit">Отправить</button>
</template>
<script>
export default {
methods: {
submit() {
this.$emit('submitForm', { id: 1, status: 'ready' })
}
}
}
</script>
Родитель
<SubmitButton @submitForm="handleSubmit" />
methods: {
handleSubmit(data) {
console.log(data.status) // ready
}
}
Использование с v-model
Когда вы хотите сделать компонент совместимым с v-model, он должен:
-
Принимать modelValue как prop.
-
Генерировать событие update:modelValue.
Дочерний:
<template>
<input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" />
</template>
<script>
export default {
props: \['modelValue'\]
}
</script>
Родитель:
<CustomInput v-model="username" />
В этом случае родитель будет обновлять username автоматически при изменении значения в дочернем компоненте.
Вложенные компоненты и прокси-события
Если компонент A содержит компонент B, а тот — компонент C, и событие генерируется в C, но родителю A нужно его обработать, можно пробросить событие из B:
В компоненте C:
this.$emit('customEvent')
В компоненте B:
<ChildC @customEvent="$emit('customEvent')" />
В компоненте A:
<ChildB @customEvent="handleIt" />
Такое "прокидывание" называется forwarding (перенаправление) событий.
Регистрирование событий в emits
Vue 3 поддерживает декларативную регистрацию возможных событий:
export default {
emits: \['submit', 'close'\]
}
Это позволяет Vue лучше отслеживать корректность использования событий и генерировать предупреждения при ошибках.
Проверка типов и валидаторов для событий
Vue 3 позволяет описывать emits как объект с валидацией аргументов:
emits: {
submit(payload) {
return typeof payload === 'object' && 'name' in payload
}
}
Если проверка не пройдёт — Vue покажет предупреждение в консоли.
События + props = однонаправленный поток
События используются в Vue, чтобы сохранить однонаправленный поток данных:
-
Родитель передаёт данные через props
-
Дочерний компонент вызывает emit, чтобы сообщить об изменении
-
Родитель обрабатывает событие и, при необходимости, обновляет props
Этот паттерн делает взаимодействие между компонентами предсказуемым и чистым.