由于在工作中vue的项目中使用了大量是全局事件总线广播,使得某些方法在某种情况下被重复多次调用,查看了一下原因,是因为在每个单文件组件中定义的事件接收器和事件广播器在页面销毁的时候没有注销导致的。于是在保证改动量不大的前提下,决定自定义一个全局事件总线文件。
之前的使用是在 main.js 文件中 vue.prototype.$eventHub = vue.prototype.$eventHub || new Vue()
因此,重新定义一个文件 EventHub.js
/**
* Created by baidm in 2021/1/3 on 12:54
*/
class EventHub {
constructor(vm) {
this.vm = vm;
this.curVm = null;
this.events = {};
this.eventMapUid = {};
}
/**
* 注册调用者实例
* @param vm
*/
$register(vm) {
this.curVm = vm;
}
/**
* 收集所有的事件类型
* @param uid
* @param type
*/
setEventMapUid(uid, type) {
if (!this.eventMapUid[uid]) {
this.eventMapUid[uid] = [];
}
this.eventMapUid[uid].push(type);
}
/**
* 收集每种类型的回调
* @param type
* @param fn
*/
$on(type, fn) {
if (!this.events[type]) {
this.events[type] = [];
}
this.events[type].push(fn);
if (this.curVm instanceof this.vm) {
this.setEventMapUid(this.curVm._uid, type);
}
}
/**
* 触发每种类型的所有回调
* @param type
* @param args
*/
$emit(type, ...args) {
if (this.events[type]) {
this.events[type].forEach(fn => fn(...args));
}
}
/**
* 取消订阅事件
* @param type
* @param fn
*/
$off(type, fn) {
if (fn && this.events[type]) {
const index = this.events[type].findIndex(f => f === fn);
if (index !== -1) {
this.events[type].splice(index, 1);
}
return;
}
delete this.events[type];
}
/**
* 取消uid订阅的所有事件
* @param uid
*/
$offAll(uid) {
const curAllTypes = this.eventMapUid[uid] || [];
curAllTypes.forEach(type => this.$off(type));
delete this.eventMapUid[uid];
}
}
export default {
install(vm, options = {}) {
Reflect.defineProperty(vm.prototype, "$eventHub", {
value: new EventHub(vm)
})
}
}
然后在 main.js 文件中定义 mixin
import Vue from 'vue'
...
import EventHub from "./EventHub"
EventHub.install(Vue);
const mixin = {
data() {
return {}
},
created() {
this.$eventHub.$register(this);
},
methods: {},
directives: {},
beforeDestroy() {
this.$eventHub.$offAll(this._uid);
}
};
Vue.mixin(mixin);
...
这样在不改变原有代码中的写法 this.$eventhub.$on() 和 this.$eventHub.$emit() 的前提下,即可在每个SFC卸载的时候自动下载在该组件中定义的事件广播。 |