Vue3移除了$on、$off和$once事件API,旨在简化API并更好地支持组合式API。
主要替代方案包括:
1)使用mitt等第三方事件库;
2)基于provide/inject和响应式状态模拟事件总线;
3)使用composable共享状态;
4)采用Pinia/Vuex进行状态管理;
5)父子组件通过props/emits通信。
Vue3鼓励使用更明确的组件通信方式,如状态管理工具和组合式API,替代传统事件总线模式,使代码更可维护。
推荐优先考虑Pinia配合provide/inject或composables方案。
Vue 3 中移除了$on、$off和$once方法
这是 Vue 3 的一项重大变化。
为什么被移除?
Vue 3 的事件 API 重构旨在:
简化 API- 减少全局方法数量
更好地支持组合式 API- 传统的事件总线模式与组合式 API 理念不太契合
促进更明确的组件通信模式- 鼓励使用更可维护的通信方式
替代方案
1.使用第三方事件库(最接近的替代)
// 安装:npm install mitt import mitt from 'mitt'; // 创建事件总线 const emitter = mitt(); // 发送事件 emitter.emit('event-name', data); // 监听事件 emitter.on('event-name', (data) => { console.log(data); }); // 取消监听 emitter.off('event-name', handler);2.使用 Vue 3 的 provide/inject + 响应式状态
// 事件总线模拟 import { reactive, provide, inject } from 'vue'; // 创建事件总线 const eventBusSymbol = Symbol(); export function createEventBus() { const listeners = reactive({}); return { on(event, callback) { if (!listeners[event]) listeners[event] = []; listeners[event].push(callback); }, off(event, callback) { if (listeners[event]) { const index = listeners[event].indexOf(callback); if (index > -1) listeners[event].splice(index, 1); } }, emit(event, data) { if (listeners[event]) { listeners[event].forEach(callback => callback(data)); } } }; } // 使用 export function useEventBus() { return inject(eventBusSymbol); }3.使用 composable 替代事件总线
// counter.js - 共享状态 import { ref, readonly } from 'vue'; export function useCounter() { const count = ref(0); const increment = () => { count.value++; // 可以在这里触发其他逻辑 }; return { count: readonly(count), increment }; } // 多个组件共享同一个实例4.使用 Vuex/Pinia 进行状态管理
// 使用 Pinia(Vue 3 推荐状态管理) import { defineStore } from 'pinia'; export const useAppStore = defineStore('app', { state: () => ({ events: [], data: null }), actions: { triggerEvent(eventName, payload) { // 处理事件逻辑 } } });5.使用 v-model 和 emits(父子组件通信)
<!-- 子组件 --> <script setup> defineProps(['modelValue']); defineEmits(['update:modelValue']); const updateValue = (newVal) => { emit('update:modelValue', newVal); }; </script> <!-- 父组件 --> <ChildComponent v-model="value" />迁移建议
父子组件通信→ 使用
props和emits兄弟组件通信→ 使用共同的父组件或状态管理
远房组件通信→ 使用 Pinia/Vuex 或 provide/inject
全局事件→ 使用
mitt等第三方库
总结
虽然$on被移除,但 Vue 3 提供了更现代化、类型安全的替代方案。
对于大多数应用,推荐使用Pinia进行状态管理,配合provide/inject或composables来替代传统的事件总线模式。