Гид по технологиям

Vue: $emit и defineEmits для отправки событий от дочерних компонентов

• 6 min read • Веб-разработка • Обновлено 21 Nov 2025
Vue: $emit и defineEmits для событий от дочерних
Vue: $emit и defineEmits для событий от дочерних

Открытый ноутбук с цветным кодом на тёмном экране и видимой рукой пользователя.

Компонентная архитектура упрощает создание и поддержку веб‑приложений. Внутри такой архитектуры компоненты общаются разными способами: props, слоты и пользовательские события. Пользовательские события позволяют передать данные от дочернего компонента к родительскому, когда нужно сообщить о действии или отправить результат.

Почему стоит использовать события из дочерних компонентов

Коротко: props идут сверху вниз, события идут снизу вверх. Это явная и простая модель взаимодействия. Поддерживаемость и читаемость кода улучшаются, если роли компонентов предельно ясны: родитель выдаёт данные через props, а дочерний сообщает изменения через события.

Важно: это не всегда единственный вариант. Для более глубокого обмена состоянием используйте provide/inject или централизованные хранилища вроде Pinia.

Именование пользовательских событий

Рекомендации по именованию:

  • В шаблонах HTML используйте kebab-case, например my-event или button-clicked.
  • В JavaScript допустим camelCase, но Vue в итоге приводят имена к kebab-case при привязке в шаблонах.
  • Выбирайте описательные имена, которые сразу показывают цель события, например item-added, form-submitted, validation-error.

Хелпер: думайте о событии как о глаголе. Название должно отвечать на вопрос Что произошло?

Два способа эмитить события в Vue

Есть два распространённых подхода:

  • $emit — встроенный метод, удобно вызывать прямо в шаблоне или в опциях компонента.
  • defineEmits — макрос composition API, который явно описывает набор событий и возвращает функцию для их отправки.

Ниже приведены оба подхода с рабочими примерами.

$emit: пример дочернего компонента





Пояснения:

  • post — локальная реактивная переменная, связанная с полем ввода через v-model.
  • При клике вызывается $emit с двумя аргументами: имя события и полезная нагрузка post.
  • Родитель может прослушать это событие и получить значение post.

Родитель, который принимает событие через @





Здесь родитель регистрирует слушатель события @button-clicked и вызывает addPosts с переданным значением.

defineEmits: пример с явным описанием событий





Преимущества defineEmits:

  • Явно видно, какие события может излучать компонент.
  • Удобно для типов и автодополнения в IDE.
  • Поддерживает более структурированный подход в composition API.

Когда это подходит, а когда нет

Когда использовать события:

  • Простая передача данных один уровень вверх.
  • Сигнализация об одноразовом действии, например submit, click, delete.
  • Поддержка модульности и слабой связанности компонентов.

Когда события не подходят:

  • Когда нужно синхронизировать состояние между многими компонентами в разных частях дерева. В этом случае лучше использовать provide/inject или централизованное хранилище.
  • Когда требуется двунаправленная синхронизация сложных структур данных. Используйте родительское состояние и props или управляйте состоянием через store.
  • Для передачи команд между не родственными компонентами рассмотрите event bus или глобальное состояние, но помните о рисках утечки памяти и отладки.

Альтернативные подходы

  • Props вниз и события вверх — стандартная модель, хороша для большинства случаев.
  • provide / inject — для передачи зависимостей глубоко вниз без пробрасывания через промежуточные компоненты.
  • Pinia / Vuex — централизованное состояние для сложных приложений.
  • Компонент‑событийная шина (event bus) — устаревающий подход, полезен в небольших проектах, но усложняет трассировку событий.

Мини‑методология: как внедрить пользовательские события правильно

  1. Определите границы ответственности компонента. Если компонент управляет своей локальной формой, он должен эмитить событие submit или change.
  2. Назовите событие описательно в kebab-case для шаблонов.
  3. В composition API используйте defineEmits для явности и типизации.
  4. В родителе обрабатывайте событие и делайте минимальную работу: обновление состояния или делегирование дальше.
  5. Покройте сценарии тестами и добавьте критерии приёмки.

Критерии приёмки

  • Компонент должен эмитить событие с ожидаемым именем при соответствующем действии.
  • Родитель корректно принимает полезную нагрузку и обновляет состояние.
  • Имя события понятно и соответствует документации компонента.
  • Не должно быть утечек подписок или глобальных слушателей, оставшихся после уничтожения компонента.

Чек‑лист для ролей

Разработчик:

  • Разработать компонент с явными событиями через defineEmits.
  • Написать unit‑тесты, которые проверяют эмиссию событий.
  • Документировать событие и формат полезной нагрузки.

Код‑ревьювер:

  • Проверить имена событий на описательность.
  • Убедиться, что нет излишней логики в обработчике события в дочернем компоненте.
  • Проверить, что parent делает минимальную работу и не дублирует логику.

Тестировщик:

  • Проверить UI‑сценарии, где событие вызывает обновление.
  • Проверить сценарии с пустой полезной нагрузкой и неверными типами.

Примеры тестовых случаев и критерии приёмки

  • При клике по кнопке дочернего компонента с заполненным полем input эмитится событие button-clicked с корректной строкой.
  • Если поле input пустое, событие либо не эмитится, либо эмитится с пустой строкой в зависимости от спецификации.
  • Родитель добавляет новый элемент в список и рендерит его.

Ментальные модели и эвристики

  • Правило двух направлений: props — вниз, events — вверх. Это базовая мемориальная модель.
  • Модель единственного источника правды: любое состояние, изменяемое несколькими компонентами, лучше вынести в общий источник.
  • Ясность ответственности: компонент отвечает за отправку сигнала, родитель — за обработку результата.

Контрпримеры: когда простые события ломаются

  • Сильно вложенные компоненты, где событие должно пройти через много промежуточных уровней. Вызов события может стать источником багов, если промежуточные компоненты не пробрасывают слушатели.
  • Когда нужно подтвердить действие на стороне сервера до обновления состояния. Тогда дочерний компонент должен эмитить событие, родитель — сделать запрос и обработать результат асинхронно.

Сопровождающая документация и совместимость

  • Vue 3 сохраняет совместимость в том, как шаблоны связываются с событиями, но синтаксис defineEmits доступен только в composition API с