Vue3 中的 Event Bus:从 Vue2 过渡到 mitt

206 阅读3分钟

随着Vue 3的发布,原有的Vue实例不再是构造函数,而是通过Vue.createApp({})来创建应用实例。这让原本在Vue 2中常用的Event Bus模式不再适用,因为新创建的应用实例没有$on$emit$once等方法。不过,Vue 3并没有让我们失去事件通信的能力,相反,它鼓励我们使用更轻量级的库来替代原有的Event Bus机制。这篇文章将介绍如何在Vue 3中使用mitt库来实现组件间通信,并分享一些个人的开发经验。

为什么要使用 Event Bus?

在开发复杂的应用时,组件间的通信是非常常见的需求。Vue 2中,我们常常使用Event Bus来解决父子组件以外的通信问题,比如兄弟组件、甚至完全没有父子关系的组件之间的通信。这种方式简单有效,但随着Vue 3的到来,我们不得不寻找新的解决方案。

选择 mitt

Vue 3官方推荐使用第三方库来替代原有的Event Bus模式,其中mitt因其体积小巧、API简洁而备受推崇。mitt的源码非常简单,只有约100行代码,这使得它成为一个理想的轻量级事件总线库。

如何在 Vue 3 中使用 mitt

首先,你需要安装mitt:

pnpm i mitt

然后可以在项目中这样使用:

// myBus.js
import mitt from 'mitt'
export default mitt()

或者将其注册为全局属性:

// main.js
import { createApp } from 'vue'
import App from './App.vue'
import mitt from 'mitt'

const app = createApp(App)
app.config.globalProperties.emitter = mitt()
app.mount('#app')

接着,我们可以封装一个hook来方便地使用这个全局事件总线:

// src/hooks/useEmitter.js
import { getCurrentInstance } from 'vue'

export default function useEmitter() {
  const internalInstance = getCurrentInstance()
  const emitter = internalInstance.appContext.config.globalProperties.emitter

  return emitter
}

实战示例

假设我们有一个包含侧边栏和头部的应用,头部有一个按钮用于切换侧边栏的展开与收起状态。我们可以使用mitt来实现这一功能。

首先,在头部组件中定义一个按钮,当点击时发射一个toggle-sidebar事件,并附带新的状态:

<template>
  <button @click="toggleSidebar">toggle</button>
</template>

<script setup>
import { ref } from 'vue'
import useEmitter from '@/hooks/useEmitter'

const sidebarOpen = ref(true)
const emitter = useEmitter()

const toggleSidebar = () => {
  sidebarOpen.value = !sidebarOpen.value
  emitter.emit('toggle-sidebar', sidebarOpen.value)
}
</script>

然后,在侧边栏组件中监听toggle-sidebar事件,并根据事件携带的信息更新侧边栏的状态:

<template>
  <aside class="sidebar" :class="{'sidebar--toggled': !isOpen}">
    {{ isOpen ? 'Open' : 'Closed' }}
  </aside>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import useEmitter from '@/hooks/useEmitter'

const isOpen = ref(true)
const emitter = useEmitter()

onMounted(() => {
  emitter.on('toggle-sidebar', (state) => {
    isOpen.value = state
  })
})
</script>

个人经验与思考

使用mitt作为Vue 3中的Event Bus,相比Vue 2中的做法更加轻量且灵活。mitt的API设计简洁明了,易于理解和使用。同时,将其注册为全局属性的方式也为组件间的通信提供了便利。

然而,值得注意的是,随着应用规模的增长,事件总线可能会成为耦合的来源。因此,在使用事件总线时,建议保持适度的使用频率,并尽量减少跨组件之间的直接依赖。此外,还可以考虑使用Vuex等状态管理库来集中管理共享状态,以保持应用的良好组织结构。

总之,尽管Vue 3对原有Event Bus模式进行了调整,但通过使用mitt等第三方库,我们依然能够轻松实现组件间的通信。这不仅体现了Vue框架的灵活性,也为开发者提供了更多的选择和可能性。