Vue 3 中如何优雅的使用eventBus(事件总线)

36,338 阅读1分钟

如果你刚开始使用Vue3,很可能会发现,原本用得得心应手的eventBus突然不灵了。

因为Vue3不再提供$onemit函数,Vue实例不再实现事件接口。官方推荐引入外部工具实现,或者自己手撸一个事件类

api变更文档:

Remove $on, $off and $once instance methods. Vue instances no longer implement the event emitter interface. -- active-rfcs/0020-events-api-change.md

如何使用

想在Vue3上把EventBus再次用起来也非常简单,大体就是三个步骤

  1. 引入/编写事件库
  2. 在入口文件中挂载
  3. 在组件中引入并使用

🤡 先在前排推荐使用Vue3-Bus插件,后面会讲如何不借助插件原生实现

1. 通过Vue3-Eventbus使用更优雅 👍👍👍

不需要在入口文件中编写额外逻辑,不需要每次引入inject函数,不需要每次为bus赋值,import进来一把梭直接用

安装

$ npm install --save vue3-eventbus

挂载

import eventBus from 'vue3-eventbus'
app.use(eventBus)

使用

// Button.vue
import bus from 'vue3-eventbus'
export default {
    setup() {
        bus.emit('foo', { a: 'b' })
    }
}

舒服了~

更多用法和配置可以参照github上的文档

2. 不借助插件的原生使用方式

1. 引入/编写事件库

  1. 直接引入官方推荐的mitt
  2. 手撸一个简单的发布/订阅类 这两种方式都没啥差别,因为代码逻辑也很简单,贴一个代码实现,可以直接copy去用
// eventBus.js
export default class EventBus{
    constructor(){
        this.events = {};
    }
    emit(eventName, data) {
        if (this.events[eventName]) {
            this.events[eventName].forEach(function(fn) {
                fn(data);
            });
        }
    }
    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;
                }
            };
        }
    }
}

2. 在入口文件中执行挂载

入口文件默认是main.js

// main.js
import { createApp } from 'vue'
import App from './App.vue'
// ① 引入事件类
// 自己编写的或者mitt皆可
import EventBus from 'lib/bus.js'
// 或者:import EventBus from 'mitt'
const $bus = new EventBus()

// ② 挂载
// 1.使用provide提供
app.provide('$bus', $bus)
// 2.挂载到this上
app.config.globalProperties.$bus = $bus

3. 在组件中引入并使用

在created中使用

// Button.vue
export default {
  created() {
      this.$bus.emit('ButtonCreated')
  }
}

在setup中使用

注意: 因为在setup中无法访问到应用实例(this),如果你需要在setup中使用eventBus,则需要通过provide/inject方式引入

// Button.vue
import { inject } from 'vue'
export default {
  setup() {
      const $bus = inject('$bus')
      $bus.emit('ButtonSetup')
  }
}

4. 使用小结

通过上面三个步骤,EventBus就可以正常使用啦,还是很简单的。不过也能看到在挂载的时候需要多写两行代码,使用的时候,每个组件在setup内都要引入inject函数,并且初始化一次。有朋友就要问了?有没有更优雅的办法咧?

没错!用了Vue3-Eventbus插件,只需要在入口文件里use一下,每个组件里引入就能直接用起来啦!