Emit и custom события

Vue.js предоставляет мощный механизм для взаимодействия компонентов через пользовательские события, что особенно важно при построении сложной архитектуры с вложенными компонентами. Основной инструмент для этого — метод $emit.


Основы $emit

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

this.$emit('имя-события', payload)
  • имя-события — строка, задающая идентификатор события.
  • payload — необязательный объект или значение, передаваемое родительскому компоненту.

Пример:

// Дочерний компонент
export default {
  methods: {
    notifyParent() {
      this.$emit('update', { message: 'Данные обновлены' });
    }
  }
}
<!-- Родительский компонент -->
<ChildComponent @update="handleUpdate" />
export default {
  methods: {
    handleUpdate(payload) {
      console.log(payload.message); // 'Данные обновлены'
    }
  }
}

Передача данных через события

$emit поддерживает передачу нескольких аргументов:

this.$emit('event-name', arg1, arg2, arg3)

Родитель может получить их через соответствующий обработчик:

<ChildComponent @event-name="handleEvent" />
methods: {
  handleEvent(arg1, arg2, arg3) {
    console.log(arg1, arg2, arg3);
  }
}

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


События и v-on с модификаторами

Vue позволяет обрабатывать события с помощью модификаторов:

  • .stopevent.stopPropagation()
  • .preventevent.preventDefault()
  • .capture — слушатель с фазой захвата
  • .once — обработка события один раз
  • .passive — слушатель пассивный, оптимизация для скроллинга

Пример:

<ChildComponent @update.once.prevent="handleUpdate" />

В этом случае событие обработается один раз, и действие по умолчанию будет предотвращено.


Декларативные пользовательские события с defineEmits (Vue 3, Composition API)

Для компонентов на Composition API Vue 3 введена функция defineEmits:

<script setup>
const emit = defineEmits(['update', 'delete'])

function notify() {
  emit('update', { id: 1 })
}
</script>
  • Список событий можно указать как массив строк.
  • Можно использовать объект для валидации типов аргументов:
const emit = defineEmits({
  update: (payload) => typeof payload.id === 'number',
  delete: (id) => typeof id === 'number'
})

Попытка вызвать событие с неправильным типом аргумента приведет к предупреждению в консоли.


События в дочерних компонентах

Для передачи события через несколько уровней компонентов используют:

  1. Промежуточные компоненты, которые просто ретранслируют события через $emit.
  2. Provide / Inject или глобальный стор, если глубина вложенности большая.

Пример ретрансляции:

export default {
  emits: ['update'],
  methods: {
    handleChildUpdate(payload) {
      this.$emit('update', payload)
    }
  }
}
<GrandchildComponent @update="handleChildUpdate" />

Практика именования событий

Рекомендации по именованию пользовательских событий:

  • Использовать kebab-case (update-item) вместо camelCase (updateItem) при использовании в шаблонах.
  • События должны быть глаголами, отражающими действие (delete-item, toggle-visibility).
  • Явное указание событий через опцию emits в компонентах Vue 3 повышает читаемость и безопасность кода.

Динамические события

Можно динамически формировать имена событий:

const eventName = `update-${item.id}`
this.$emit(eventName, item)

Родительский компонент может обрабатывать их через v-on с вычисляемыми ключами:

<ChildComponent v-for="item in items" :key="item.id" @update-[item.id]="handleUpdate" />

В Vue 3 поддерживается синтаксис v-on="object" для передачи множества обработчиков динамически:

const handlers = {
  'update-1': () => {},
  'update-2': () => {}
}
<ChildComponent v-on="handlers" />

Отличие событий от props

  • Props — данные, передаваемые сверху вниз (родитель → ребенок).
  • Emit — события, передаваемые снизу вверх (ребенок → родитель).

Использование $emit и props обеспечивает односторонний поток данных, что повышает предсказуемость приложения и упрощает отладку.


Заключение по практическому использованию

  • $emit обеспечивает чистую и предсказуемую связь компонентов.
  • Определение событий через emits в Vue 3 повышает безопасность и контроль типов.
  • Использование модификаторов событий позволяет легко управлять поведением событий.
  • Динамические события и ретрансляция расширяют возможности передачи данных через сложные деревья компонентов.

Эти принципы формируют основу архитектуры компонентов Vue.js, где каждая часть приложения остается изолированной, но гибко взаимодействующей с другими.