логотип PurpleSchool
логотип PurpleSchool

Когда и как использовать $emit и call во Vue

Автор

Олег Марков

Введение

Когда вы работаете с компонентами во Vue, одна из главных задач — правильно строить обмен данными между ними. Чаще всего родительский компонент передает данные ребенку через props, но бывает нужно отправить информацию обратно — от ребенка родителю. Для этой задачи во Vue используется механизм событий, основанный на методе $emit. Кроме этого, иногда нужна противоположная задача — вызвать метод у дочернего компонента из родителя. Тогда используется прямой вызов метода через $refs и метод call.

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

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

Как работает $emit

Метод $emit — фундаментальный инструмент для связи между дочерними и родительскими компонентами. Если вы хотите, чтобы дочерний компонент сообщил о каком-то действии (например, пользователь нажал кнопку, заполнил форму и т.д.), используйте $emit.

Пример — базовый механизм $emit

Смотрите, вот простой пример:

<template>
  <button @click="notifyParent">Отправить событие</button>
</template>

<script>
export default {
  methods: {
    notifyParent() {
      // Событие 'childClicked' будет отправлено в родительский компонент
      this.$emit('childClicked', 'Некоторые данные');
    }
  }
}
</script>

Теперь в родительском компоненте вы можете "подслушивать" это событие:

<template>
  <ChildComponent @childClicked="handleChildClick"/>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: { ChildComponent },
  methods: {
    handleChildClick(payload) {
      // payload содержит 'Некоторые данные'
      // Здесь можно выполнить нужное действие
    }
  }
}
</script>

Когда использовать $emit

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

Пример с формой

Вот как работает обратная передача значения инпута в родитель:

<template>
  <input :value="value" @input="updateValue">
</template>

<script>
export default {
  props: ['value'],
  methods: {
    updateValue(event) {
      this.$emit('input', event.target.value);
    }
  }
}
</script>

Родитель обрабатывает это так:

<MyInput v-model="parentValue"/>

Компонент <MyInput> будет работать как полноценный v-model благодаря правильному использованию $emit('input', ...).

Особенности и best practices использования $emit

  • Старайтесь использовать события как интерфейс взаимодействия между компонентами.
  • Не стоит изменять состояние родителя напрямую через $parent — используйте события.
  • Именуйте события осмысленно — например, open, close, update:value.
  • События — односторонняя связь (child -> parent).

Множественные параметры и типы событий

Можно передать несколько параметров:

this.$emit('eventName', param1, param2);

Родитель принимает их:

handleEvent(param1, param2) {
  // Работаете с двумя параметрами
}

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

Ограничения $emit

  • Событие нельзя "услышать" выше ближайшего родителя в иерархии компонентов.
  • Передача через несколько уровней становится неудобной — в таких случаях лучше использовать state management (например, Vuex или Pinia).

Вызов методов через call и $refs

Когда возникает необходимость в вызове методов другого компонента

Иногда из родителя требуется напрямую вызвать функцию дочернего компонента. Это часто бывает при сложных UI-компонентах (например, модальные окна, сложные списки), когда событие недостаточно выразительное, и нужно управлять поведением дочернего компонента: сбрасывать форму, открывать или закрывать элемент, запускать анимацию и т.д.

Для этого используется доступ к компоненту через ref и вызов метода.

Как использовать $refs и call

Шаг 1. Даем дочернему компоненту ref

В шаблоне родительского компонента пишем:

<ChildComponent ref="myChild"/>

Шаг 2. Вызываем метод через ref

В сборщике методов или жизненном цикле родительского компонента делаем так:

methods: {
  callChildMethod() {
    // this.$refs.myChild ссылается на экземпляр дочернего компонента
    this.$refs.myChild.childMethod('аргумент');
  }
}

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

export default {
  methods: {
    childMethod(payload) {
      // Выполняем необходимые действия
      // payload содержит данные от родителя
    }
  }
}

Когда использовать этот подход

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

Пример: сбросить внутреннюю форму дочернего компонента

// Родительский компонент
methods: {
  resetChildForm() {
    this.$refs.childFormRef.resetForm();
  }
}

// Дочерний компонент
methods: {
  resetForm() {
    // Очищаем поля формы
    this.formData = {};
  }
}

Возможности и ограничения $refs и call

  • Позволяет напрямую вызывать любые методы у дочернего компонента.
  • Работает только для дочерних компонентов, которые уже смонтированы (ref будет доступен после mount).
  • Не работает для функциональных компонентов и компонентов, не имеющих экземпляра (stateless components).
  • Не рекомендуется использовать для управления несколькими уровнями вложенности — усложняет структуру и контроль.

Теория: что такое call в данном контексте

Во Vue специального метода call как встроенного нет. Здесь мы используем обычный вызов метода объекта (экземпляра компонента), полученного через $refs. То есть call в контексте Vue — это просто вызов метода, но иногда в коде или диалогах разработчики имеют в виду component.method.call(context, args) из JavaScript. Как правило, стандартный вызов component.method() достаточно, так как в контексте экземпляра метода this уже корректно привязан.

На что обратить внимание при использовании $refs

  • Не пытайтесь использовать $refs до монтирования компонента — они будут равны undefined.
  • Не стоит чрезмерно полагаться на ручное управление дочерними через $refs — это признак tight coupling (плотного связывания), старайтесь разделять компоненты логически.
  • Для массовых операций или управления данными все равно стоит использовать события или глобальное состояние.

Тонкости и лучшие практики: отличие $emit и вызова методов

$emit — для событий и оповещений (child -> parent)

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

Вызов метода через $refs — для команд (parent -> child)

  • Управление дочерним компонентом непосредственно.
  • Часто используется для компонентов с внутренним сложным стейтом.
  • Усиливает связанность между компонентами — старайтесь минимизировать избыточное использование.

Сценарии, когда эти подходы комбинируются

Иногда ваш компонент и отправляет события родителю ($emit), и сам должен реагировать на команды родителя (например, сбрасываться или обновляться). Это нормально, главное — разграничивать, за что отвечает каждый канал связи.

Заключение

В функциональной экосистеме Vue важно понимать, как компоненты взаимодействуют друг с другом. $emit — основной способ передачи данных от ребенка к родителю через события, что позволяет строить модульные и независимые интерфейсы. В то же время, иногда родителю необходимо более тесно управлять дочерними компонентами — тогда на помощь приходит доступ по $refs и вызов методов. Принимая решения о выборе инструмента, ориентируйтесь на читаемость и устойчивость архитектуры, избегайте перегруженности связями и внимательно следите за вложенностью и зависимостями компонентов. Назначение $emit — коммуникация событий, у $refs — ручное ("императивное") управление компонентом.


Частозадаваемые технические вопросы и ответы

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

Для передачи данных через несколько уровней компонентов используйте паттерн "Провайдер/Инъектор" (provide/inject) или центральное хранилище (например, Vuex/Pinia). События через $emit не проходят выше ближайшего родителя по компонентам.

Как правильно типизировать события, если используется TypeScript?

Опишите интерфейсы событий в defineEmits/defineProps (Vue 3) или используйте JSDoc на методах, вызывающих $emit. Для строгой типизации в применяйте функцию defineEmits с описанием типов событий.

Можно ли вызывать методы у нескольких дочерних компонентов одновременно через $refs?

Да, если вы используете v-for для создания массива дочерних, то $refs станет массивом. Например: с v-for даёт this.$refs.children как массив ссылок на компоненты. Циклом можно вызывать нужные методы у всех.

Что делать, если $refs возвращает undefined?

Проверьте, что компонент уже отрисован (например, используйте mounted), что ref задан корректно в шаблоне и что компонент не статичный/функциональный (иначе не будет работать).

Как декларировать кастомные события для v-model во Vue 3?

Для v-model во Vue 3 имя кастомного события должно быть update:modelValue. В дочернем компоненте вызовите this.$emit('update:modelValue', value), чтобы работали двусторонние биндинги.


Стрелочка влевоПонимание и работа с компилятором VueВзаимодействие с внешними API через Axios в VueСтрелочка вправо

Все гайды по Vue

Руководство по валидации форм во Vue.jsИнтеграция Tiptap для создания редакторов на VueРабота с таблицами во Vue через TanStackИнструкция по установке и компонентам Vue sliderУправление пакетами Vue js с помощью npmУправление пакетами и node modules в Vue проектахКак использовать meta для улучшения SEO на VueПолный гайд по компоненту messages во Vuejs5 правил использования Inertia с Vue и LaravelРабота с модулями и пакетами в VueИнструкция по работе с grid на VueGithub для Vue проектов - подробная инструкция по хранению и совместной работеНастройка ESLint для Vue проектов и поддержка качества кодаОбработка ошибок и отладка в Vue.jsИспользование Vue Devtools для отладки и мониторинга приложенийРабота с конфигурационными файлами и скриптами VueСоздание и настройка проектов Vue с помощью Vue CLI3 способа интеграции Chart.js с Vue для создания графиковРабота с Canvas во VueИнструкция по реализации календаря во VueРабота с Ant Design Vue для создания UI на Vue
Обзор и использование утилит Vue для удобной разработкиРабота с обновлениями компонента и жизненным циклом updateРазрешение конфликтов и ошибок с помощью Vue resolveИспользование query-параметров и их обработка в маршрутах VueЗагрузка и управление состоянием загрузки в VueИспользование библиотек Vue для расширения функционалаРабота с JSON данными в приложениях VueКак работать с экземплярами компонента Instance во VueПолучение данных и API-запросы во Vue.jsЭкспорт и импорт данных и компонентов в VueОбработка событий и их передача между компонентами VuejsГайд по defineEmits на Vue 3Понимание core функционала Vue и его применениеПонимание и применение Composition API в Vue 3Понимание и работа с компилятором VueКогда и как использовать $emit и call во VueВзаимодействие с внешними API через Axios в Vue
Веб приложения на Vue архитектура и лучшие практикиИспользование Vite для быстрого старта и сборки проектов на Vue 3Работа с URL и ссылками в приложениях на VueРабота с пользовательскими интерфейсами и UI библиотеками во VueОрганизация и структура исходных файлов в проектах VueИспользование Quasar Framework для разработки на Vue с готовыми UI-компонентамиОбзор популярных шаблонов и стартовых проектов на VueИнтеграция Vue с PHP для создания динамичных веб-приложенийКак организовать страницы и маршруты в проекте на VueNuxt JS и Vue 3 для SSR приложенийСоздание серверных приложений на Vue с помощью Nuxt jsИспользование Vue Native для разработки мобильных приложенийОрганизация и управление индексной страницей в проектах VueИспользование Docker для контейнеризации приложений на VueИнтеграция Vue.js с Django для создания полноценных веб-приложенийСоздание и работа с дистрибутивом build dist Vue приложенийРабота со стилями и CSS в Vue js для красивых интерфейсовСоздание и структурирование Vue.js приложенияКак исправить ошибку cannot find module vueНастройка и сборка проектов Vue с использованием современных инструментовИнтеграция Vue с Bitrix для корпоративных решенийРазработка административных панелей на Vue js
Интеграция Tailwind CSS с Vue для современных интерфейсов5 библиотек для создания tree view во VueИнтеграция Vue с серверной частью и HTTPS настройкамиКак обрабатывать async операции с Promise во VueИнтеграция Node.js и Vue.js для разработки приложенийРуководство по интеграции Vue js в NET проектыПримеры использования JSX во VueГайд по импорту и регистрации компонентов на VueМногоязычные приложения на Vue с i18nИнтеграция FLIR данных с Vue5 примеров использования filter во Vue для упрощения разработки3 примера реализации drag-and-drop во Vue
Управление переменными и реактивными свойствами во VueИспользование v for и slot в VueПрименение v-bind для динамической привязки атрибутов в VueУправление пользователями и их данными в Vue приложенияхСоздание и использование UI Kit для Vue приложенийТипизация и использование TypeScript в VuejsИспользование шаблонов в Vue js для построения интерфейсовИспользование Swiper для создания слайдеров в VueРабота со стилями и стилизацией в VueСтруктура и особенности Single File Components SFC в VueРабота со SCSS в проектах на Vue для стилизацииРабота со скроллингом и прокруткой в Vue приложенияхПрименение script setup синтаксиса в Vue 3 для упрощения компонентовИспользование scoped стилей для изоляции CSS в компонентах Vue3 способа улучшить навигацию Vue с push()Обработка запросов и асинхронных операций в VueПонимание и использование provide inject для передачи данных между компонентамиПередача и использование props в Vue 3 для взаимодействия компонентовПередача данных между компонентами с помощью props в Vue jsУправление property и функциями во Vue.jsРабота со свойствами компонентов VueУправление параметрами и динамическими данными во VueРабота с lifecycle-хуком onMounted во VueОсновы работы с объектами в VueПонимание жизненного цикла компонента Vue js на примере mountedИспользование модальных окон modal в Vue приложенияхИспользование методов в компонентах Vue для обработки логикиИспользование метода map в Vue для обработки массивовИспользование хуков жизненного цикла Vue для управления состоянием компонентаРабота с ключами key в списках и компонентах VueОбработка пользовательского ввода в Vue.jsРабота с изображениями и их оптимизация в VueИспользование хуков жизненного цикла в VueОрганизация сеток и гридов для верстки интерфейсов на VueСоздание и управление формами в VueОрганизация файлов и структура проекта Vue.jsКомпоненты Vue создание передача данных события и emitРабота с динамическими компонентами и данными в Vue3 способа манипулирования DOM на VueРуководство по div во VueИспользование директив в Vue и их расширенные возможностиОсновы и применение директив в VueИспользование директив и их особенности на Vue с помощью defineИспользование компонентов datepicker в Vue для выбора датОрганизация циклов и итераций во VueКак работает компиляция Vue CoreСоздание и использование компонентов в Vue JSОбработка кликов и пользовательских событий в VueИспользование классов в Vue для организации кода и компонентовИспользование директивы checked для управления состоянием чекбоксов в VueГайд на checkbox компонент во VueОтображение данных в виде графиков с помощью Vue ChartСоздание и настройка кнопок в VueСоздание и настройка кнопок в Vue приложенияхРабота с lifecycle-хуками beforeCreate и beforeMount во VueИспользование массивов и методов их обработки в VueИспользование массивов и их обработка в Vue
Использование Vuetify для создания современных интерфейсов на VueИспользование transition во VueТестирование компонентов и приложений на VueРабота с teleport для управления DOM во VueПять шагов по настройке SSR в VuejsИспользование Shadcn UI компонентов с Vue для продвинутых интерфейсовИспользование router-link для навигации в Vue RouterКак использовать require в Vue для динамического импорта модулейРабота с динамическим рендерингом и виртуальным DOM на Vue.jsИспользование ref для управления ссылками и реактивностью в Vue 3Использование Vue Pro и его преимущества для профессиональной разработкиРуководство по nextTick для работы с DOMСоздание и использование компонентов с помощью Vue js и CУправление состоянием и реактивностью через inject и provideДинамическое обновление компонентов и данных на VueГлубокое изучение документации Vue и как эффективно её использоватьИспользование Crystal с Vue для разработкиИспользование вычисляемых свойств для динамического отображения данных на Vue jsОптимизация производительности и предупреждения в Vue
Открыть базу знаний