Vue3.0 项目中使用事件总线

577 阅读1分钟

image.png

vue2.x的项目里,通过 new 一个 Vue 实例的方式,让它来充当事件总线,管理非父子组件之间的事件派发响应。

  1. 先创建一个eventHub.js文件,编辑如下
import Vue from "vue";
const eventHub = new Vue();
export default eventHub;
  1. 监听事件的vue组件
import eventHub from "@/eventHub.js";

export default {
  name: '监听事件的组件',
  created() {
    eventHub.$on("event-name", this.handler);
  },
  methods: {
    handler(params) {
    	console.log('event-name handler', params);
    },
  },
};
  1. 派发事件的vue组件
import eventHub from "@/eventHub.js";

export default {
  name: '派发事件的组件',
  Mounted() {
    eventHub.$emit("event-name", 'some params');
  },
};

Vue3.0 中取消 emit 的变动,使得没法再按上面的方式使用了。官方建议使用第三方库mitt

  1. 安装
npm install --save mitt
  1. 注册使用

创建一个eventHub.js文件

import Mitt from 'mitt'

const eventHub = new Mitt();

eventHub.$on = eventHub.on;
eventHub.$off = eventHub.off;
eventHub.$emit = eventHub.emit;

export default eventHub;
  1. 将事件总线注册到 Vue 实例 在main.js
import {createApp} from 'vue'
import App from "./App.vue"
import eventHub from '@/plugins/eventHub.js';

const app = createApp(App);

// 配置全局事件总线
app.config.globalProperties.eventHub = eventHub;

app.mount('#app');
  1. 监听事件的组件
import { getCurrentInstance, onMounted } from 'vue';

export default {
  name: 'YourComponent',
  setup() {
    const eventHandler = async (params) => {
      // some async process
    };

    const { eventHub } = getCurrentInstance().proxy;
    eventHub.$on('event-name', eventHandler);

    onBeforeUnmount(() => {
      eventHub.$off('event-name', eventHandler);
    });
  },
};
  1. 派发事件的组件
import { getCurrentInstance, onMounted } from 'vue';

export default {
  name: '',
  setup() {
    const { eventHub } = getCurrentInstance().proxy;
    
    onMounted(() => {
      eventHub.$emit('event-name', 'some params');
    });
  },
};

注:

  • 上面封装的时候,使用$emit / $on / $off,是为了方便 Vue2.x的项目做迁移
  • 注意监听要在派发之前,Vue3.0中生命周期的调用顺序要清楚

动动小手,简单实现一个上面的mitt工具类。

class EventHub {
  constructor() {
    this.pool = {}
  }

  $on(event, handler) {
    this.pool[event] = this.pool[event] || new Set();

    this.pool[event].add(handler);
  }

  $off(event, handler) {
    this.pool[event].delete(handler);
  }

  $emit(event, params) {
    const handlers = this.pool[event];
    if (!handlers || !handlers.size) return;
    handlers.forEach(fn => {
      fn(params);
    })
  }

  $clear(event) {
    this.pool[event] = undefined;
  }

  $clearAll() {
    this.pool = {};
  }

}

const eventHub = new EventHub();

export default eventHub;

使用方式与上方一致,代码无需改动,效果无异。

问:如果再要实现一个$once呢?聪明的你来实现一下吧。


码路工人公众号