vue2.x的项目里,通过 new 一个 Vue 实例的方式,让它来充当事件总线,管理非父子组件之间的事件派发响应。
- 先创建一个
eventHub.js
文件,编辑如下
import Vue from "vue";
const eventHub = new Vue();
export default eventHub;
- 监听事件的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);
},
},
};
- 派发事件的vue组件
import eventHub from "@/eventHub.js";
export default {
name: ‘派发事件的组件‘,
Mounted() {
eventHub.$emit("event-name", ‘some params‘);
},
};
Vue3.0 中取消 emit 的变动,使得没法再按上面的方式使用了。官方建议使用第三方库mitt
。
- 安装
npm install --save mitt
- 注册使用
创建一个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;
- 将事件总线注册到 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‘);
- 监听事件的组件
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);
});
},
};
- 派发事件的组件
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
呢?聪明的你来实现一下吧。