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
呢?聰明的你來實現一下吧。