<p>如何在 Vue 3 中创建事件总线?</p>
<hr />
<p>在 Vue 2 中,它是:</p>
<pre class="brush:js;toolbar:false;">export const bus = new Vue();
</pre>
<pre class="brush:js;toolbar:false;">bus.$on(...)
bus.$emit(...)
</pre>
<hr />
<p>在 Vue 3 中,<code>Vue</code> 不再是构造函数,并且 <code>Vue.createApp({});</code> 返回一个没有 <code>$on</code> 的对象 code> 和 <code>$emit</code> 方法。</p>
在 Vue.js 版本 3 上,您可以使用第三方库,也可以使用以发布者-订阅者(PubSub 概念)编程模式编写的功能。
事件.js
//events - a super-basic Javascript (publish subscribe) pattern class Event{ constructor(){ this.events = {}; } on(eventName, fn) { this.events[eventName] = this.events[eventName] || []; this.events[eventName].push(fn); } off(eventName, fn) { if (this.events[eventName]) { for (var i = 0; i < this.events[eventName].length; i++) { if (this.events[eventName][i] === fn) { this.events[eventName].splice(i, 1); break; } }; } } trigger(eventName, data) { if (this.events[eventName]) { this.events[eventName].forEach(function(fn) { fn(data); }); } } } export default new Event();index.js
import Vue from 'vue'; import $bus from '.../event.js'; const app = Vue.createApp({}) app.config.globalProperties.$bus = $bus;按照官方文档中的建议,您可以使用 mitt 库在组件之间调度事件,假设我们有一个侧边栏和
header 其中包含一个关闭/打开侧边栏的按钮,我们需要该按钮来切换侧边栏组件内的某些属性:在 main.js 中导入该库并创建该发射器的实例并定义为 全局属性:
安装:
用法:
import { createApp } from 'vue' import App from './App.vue' import mitt from 'mitt'; const emitter = mitt(); const app = createApp(App); app.config.globalProperties.emitter = emitter; app.mount('#app');在标头中发出带有一些负载的
toggle-sidebar事件:<template> <header> <button @click="toggleSidebar"/>toggle</button> </header> </template> <script > export default { data() { return { sidebarOpen: true }; }, methods: { toggleSidebar() { this.sidebarOpen = !this.sidebarOpen; this.emitter.emit("toggle-sidebar", this.sidebarOpen); } } }; </script>在侧边栏中接收带有有效负载的事件:
<template> <aside class="sidebar" :class="{'sidebar--toggled': !isOpen}"> .... </aside> </template> <script> export default { name: "sidebar", data() { return { isOpen: true }; }, mounted() { this.emitter.on("toggle-sidebar", isOpen => { this.isOpen = isOpen; }); } }; </script>对于那些使用组合 API 的人,他们可以使用
emitter,如下所示:创建文件 src/composables/useEmitter.js
import { getCurrentInstance } from 'vue' export default function useEmitter() { const internalInstance = getCurrentInstance(); const emitter = internalInstance.appContext.config.globalProperties.emitter; return emitter; }从那里开始,您可以使用
useEmitter,就像使用useRouter一样:import useEmitter from '@/composables/useEmitter' export default { setup() { const emitter = useEmitter() ... } ... }使用组合 API
您还可以受益于新的组合 API 并定义可组合事件总线:
eventBus.js
import { ref } from "vue"; const bus = ref(new Map()); export default function useEventsBus(){ function emit(event, ...args) { bus.value.set(event, args); } return { emit, bus } }在组件 A 中执行以下操作:
import useEventsBus from './eventBus'; ... //in script setup or inside the setup hook const {emit}=useEventsBus() ... emit('sidebarCollapsed',val)在组件 B 中:
const { bus } = useEventsBus() watch(()=>bus.value.get('sidebarCollapsed'), (val) => { // destruct the parameters const [sidebarCollapsedBus] = val ?? [] sidebarCollapsed.value = sidebarCollapsedBus })