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

Как правильно отправлять пользовательские события в Vue

5 min read Frontend Обновлено 09 Jan 2026
Отправка событий в Vue: $emit и defineEmits
Отправка событий в Vue: $emit и defineEmits

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

Структурирование веб-приложений через компонентную архитектуру упрощает разработку и сопровождение. Обмен данными между компонентами можно реализовать разными способами: props и slots для передачи вниз, а пользовательские события — для передачи вверх. Пользовательские события позволяют дочернему компоненту отправить данные родителю.

Отправка событий от дочернего к родительскому компоненту

Vue предоставляет несколько механизмов для связи между компонентами. Props — удобный способ отправить данные от родителя к дочернему компоненту. Когда нужно передать данные в обратном направлении, дочерний компонент может «эмитить» (отправлять) пользовательские события, которые слушает родитель.

Пример жизненной ситуации: есть компонент кнопки, который при каждом клике формирует строку или объект. Чтобы родитель обновил своё состояние или выполнил действие, дочерний компонент должен отправить событие с полезной нагрузкой (payload).

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

До Vue 3 на практике рекомендовали использовать kebab-case (нижнее подчёркивание через дефис) для имен событий. Сейчас принято:

  • В HTML-шаблонах — kebab-case (например, button-clicked).
  • В JavaScript — camelCase допустим, но Vue приведёт имена к kebab-case при компиляции.

Главное — выбирать понятные, описательные имена, чтобы коллеги сразу понимали назначение события.

Как отправлять пользовательские события: обзор вариантов

Есть два основных подхода в компонентах Vue:

  1. Вызвать встроенный $emit прямо в шаблоне или скрипте.
  2. Использовать defineEmits (Vue 3) для явного объявления событий и получения функции emit.

Ниже — практические примеры и рекомендации.

Использование $emit в дочернем компоненте

$emit — встроенный метод Vue, который позволяет дочернему компоненту отправить событие родителю. Метод принимает имя события и необязательную полезную нагрузку.

Пример дочернего компонента, который отправляет событие при клике:





Объяснение шагов:

  • Создаётся реактивная переменная post.
  • v-model связывает ввод с переменной post.
  • При клике выполняется $emit(‘button-clicked’, post) — родитель получает имя события и ссылку на post (в этом примере — реактивный объект).

Родительский компонент слушает событие так (аналогично исходному примеру):





Важно: при передаче сложных объектов думайте о копировании/мутациях — иногда полезно отправлять примитив или клон объекта, чтобы избежать неожиданных реактивных побочных эффектов.

Использование defineEmits в Vue 3

defineEmits позволяет явно объявить набор событий, которые компонент может отправлять. Это улучшает читаемость и упрощает работу с типами (если вы используете TypeScript).

Пример:





Отличия от $emit:

  • defineEmits даёт вам функцию emit, но при этом вы заранее объявляете допустимые имена событий.
  • В TypeScript вы можете объявить сигнатуры событий — это повышает типобезопасность.

Как родитель обрабатывает событие и что важно помнить

  • В шаблоне родителя используйте синтаксис @event-name или v-on:event-name.
  • Передавайте в обработчик только то, что нужно: примитивы или чистые объекты.
  • Вложенность компонентов увеличивает сложность передачи данных вверх — подумайте о pattern-ах (provide/inject или глобальное состояние).

Важно

Если вы отправляете реактивный объект напрямую и меняете его в родителе, исходный объект в дочернем компоненте тоже изменится — это может быть как полезно, так и привести к багам.

Альтернативные подходы и когда их использовать

  • provide/inject — удобно для передачи данных и функций на глубоко вложенные уровни без прокидывания через каждый промежуточный компонент.
  • Глобальное хранилище (Pinia, Vuex) — для состояния приложения, доступного в разных частях приложения.
  • Event bus (событийный шина) — устаревающий подход; нежелателен в больших приложениях из-за сложности отслеживания источников событий.
  • $attrs/$listeners — передача слушателей вниз и дальше.
  • Колбэки через props — можно передать функцию из родителя в дочерний компонент и вызывать её напрямую.

Контрпример / когда события не подходят

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

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

  • Однонаправленный поток данных: props — сверху вниз; события — снизу вверх.
  • Минимизируйте количество событий — переизбыток повышает когнитивную нагрузку.
  • Для простых UI-компонентов используйте $emit или defineEmits; для бизнес-логики — глобальное состояние.

Мини‑методология: как вводить эмиты в компонент (шаги)

  1. Решите, какое событие нужно и какая полезная нагрузка будет передаваться.
  2. Выберите имя события в kebab-case для шаблона (и camelCase в скриптах, если хотите).
  3. Для Vue 3 предпочтительно объявить события через defineEmits.
  4. В родителе явно создайте обработчик и протестируйте сценарии: пустая строка, большие объекты, многократные клики.
  5. Добавьте документацию к компоненту (какие события эмитятся и с какими типами данных).

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

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

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

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

  • Объявил events (defineEmits) или использовал $emit.
  • Проверил поведение при пустой и валидной нагрузке.
  • Документировал события в README компонента.

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

  • Имена событий понятны и последовательны.
  • Payload минимален и предсказуем.
  • Нет прямых мутаций входящих props.

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

  • Покрыт сценарий успешной отправки.
  • Проверка поведения при быстром многократном клике.

Примеры расширений и шаблонов

TypeScript-подпись для defineEmits:

Mermaid-диаграмма принятия решения (когда использовать событие):

flowchart TD
  A[Нужно ли передать данные вверх?] -->|да| B{Доступ к родителю напрямую}
  B -->|да| C[Использовать $emit/defineEmits]
  B -->|нет| D{Нужно ли состояние в разных ветках?}
  D -->|да| E[Использовать глобальное хранилище]
  D -->|нет| F[Использовать provide/inject]

Риски и базовые меры смягчения

  • Риск: непреднамеренные мутации реактивных объектов. Мера: отправлять копию или примитив.
  • Риск: много однотипных событий усложняет поддержку. Мера: агрегировать события или использовать централизованное состояние.
  • Риск: коллизии имён событий в больших командах. Мера: соглашение об именовании (префиксы, доменные имена).

Когда стоит переходить на глобальное состояние

  • Когда одно и то же состояние нужно в нескольких несвязанных частях приложения.
  • Когда взаимодействия между компонентами включают транзакции или сложные бизнес-правила.

Краткая сводка

Отправка пользовательских событий — идиоматичный способ передачи данных от дочерних компонентов к родительским в Vue. Для большинства случаев достаточно $emit или defineEmits; для масштабных приложений рассмотрите глобальные хранилища или provide/inject. Документируйте события, минимизируйте payload и следуйте соглашениям об именовании.

Важно

Опишите в документации компонента, какие события он эмитит и какие типы данных ожидаются — это упростит интеграцию и поддержку в команде.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

RDP: полный гид по настройке и безопасности
Инфраструктура

RDP: полный гид по настройке и безопасности

Android как клавиатура и трекпад для Windows
Гайды

Android как клавиатура и трекпад для Windows

Советы и приёмы для работы с PDF
Документы

Советы и приёмы для работы с PDF

Calibration в Lightroom Classic: как и когда использовать
Фото

Calibration в Lightroom Classic: как и когда использовать

Отключить Siri Suggestions на iPhone
iOS

Отключить Siri Suggestions на iPhone

Рисование таблиц в Microsoft Word — руководство
Office

Рисование таблиц в Microsoft Word — руководство