# Удалено API для событий
кардинальное изменение
# Обзор
Методы экземпляров $on
, $off
и $once
были удалены. Экземпляры компонентов больше не реализуют интерфейс эмиттера событий.
# Синтаксис в 2.x
В версии 2.x, экземпляр Vue можно было использовать для вызова обработчиков, которые привязывались императивно через API эмиттера событий ($on
, $off
и $once
). Это можно было использовать для реализации шины событий и создания глобальных прослушивателей событий, используемых во всем приложении:
// eventBus.js
const eventBus = new Vue()
export default eventBus
2
3
4
5
// ChildComponent.vue
import eventBus from './eventBus.js'
export default {
mounted() {
// привязка слушателя к шине событий
eventBus.$on('custom-event', () => {
console.log('Вызвано пользовательское событие!')
})
},
beforeDestroy() {
// удаление слушателя из шины событий
eventBus.$off('custom-event')
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// ParentComponent.vue
import eventBus from './eventBus.js'
export default {
methods: {
callGlobalCustomEvent() {
eventBus.$emit('custom-event') // если ChildComponent примонтирован, то появится сообщение в консоли
}
}
}
2
3
4
5
6
7
8
9
10
# Что изменилось в 3.x
Из экземпляра полностью удалены методы $on
, $off
и $once
. Метод $emit
всё ещё является частью существующего API, так как он используется для запуска обработчиков событий, декларативно прикреплённых к родительским компонентам.
# Стратегия миграции
Флаг сборки для миграции: INSTANCE_EVENT_EMITTER
Во Vue 3 больше нет возможности использовать эти API чтобы прослушивать генерируемые события в компоненте в других компонентах, для подобного применения нет пути миграции.
# События корневого компонента
Статические слушатели событий можно добавить в корневой компонент, передавая их в качестве входных параметров в createApp
:
createApp(App, {
// Прослушивание события 'expand'
onExpand() {
console.log('expand')
}
})
2
3
4
5
6
# Шина событий
Паттерн шины событий можно использовать с помощью внешней библиотеки, реализующей интерфейс эмиттера событий, например mitt (opens new window) или tiny-emitter (opens new window).
Например:
// eventBus.js
import emitter from 'tiny-emitter/instance'
export default {
$on: (...args) => emitter.on(...args),
$once: (...args) => emitter.once(...args),
$off: (...args) => emitter.off(...args),
$emit: (...args) => emitter.emit(...args)
}
2
3
4
5
6
7
8
9
Это обеспечивает такой же API событий, как и во Vue 2.
В большинстве случаев не рекомендуется использовать глобальную шину событий для коммуникации между компонентами. Хотя это часто кажется самым простым решением, но в долгосрочной перспективе оно почти всегда оказывается головной болью в поддержке. В зависимости от обстоятельств есть различные альтернативы применению шины событий:
- Входные параметры и события должны быть основным выбором для общения между родителями и дочерними компонентами. Соседние компоненты могут общаться через своего родителя.
- Provide и inject позволяют компоненту взаимодействовать с содержимым своего слота. Это полезно для тесно связанных компонентов, которые всегда используются вместе.
provide
/inject
также можно использовать для связи компонентов на большом расстоянии. Это может помочь избежать «прокидывания» входных параметров, когда потребуется передать данные через несколько уровней компонентов, которым эти данные не нужны.- Прокидывание входных параметров можно также избежать путём рефакторинга для использования слотов. Если промежуточный компонент не нуждается в этих входных параметрах, это может указывать на проблему с разделением ответственности. Внедрение слота в этот компонент позволит родительскому предоставлять содержимое для слота самостоятельно, так что входной параметр можно будет передать напрямую, без участия промежуточного компонента.
- Глобальное управление состоянием, например с помощью Vuex (opens new window).