1.事件總線介紹
在vue中跨越層級的兩個組件進行通信,若使用props傳值和$emit觸發的方式會十分繁瑣,而事件總線的通信方式更適合跨越層級的組件通信。
2.事件總線原理
事件總線可以用一個對象來表示每一個事件 都有一個數組來記錄這個事件的監聽者
{ "event1": [hander1, hander2], "event2": [hander1, hander2, hander3], }
若給某個事件添加監聽者,就把處理函數添加到這個事件對應的數組中去
若給某個事件取消監聽者,就從這個事件對應的數組刪除這個處理函數
若要觸發某個事件,就讓這個事件對應的數組存放的處理函數依次執行
用class模擬一個事件總線
// 事件總線 class Bus { constructor() { // 用來記錄事件和監聽該事件的數組 this.listeners = {}; } // 添加指定事件的監聽者 $on(eventName, handler) { this.listeners[eventName].add(handler); } // 取消監聽事件 $off(eventName, handler) { this.listeners[eventName].delete(handler); } // 觸發事件 $emit(eventName, ...args) { this.listeners[eventName].forEach((fn) => fn(...args)); } }
3.事件總線的使用
在main.js中,引入事件總線
import Vue from 'vue'; import App from './App.vue'; import router from './router/index.js'; // 將事件總線作為Vue.prototype的屬性,方便每個組件中通過this.$bus獲取事件總線 Vue.prototype.$bus = new Vue({}); new Vue({ el: '#app', render: (h) => h(App), router, });
直接使用vue實例作為事件總線,是因為vue實例上本身就具有這三個方法($on、$emit、$off)
home.vue中觸發事件總線的事件
<template> <div> <button @click="handleClick">點擊</button> <!-- 使用test-comp組件 --> <test-comp></test-comp> </div> </template> <script> import testComp from './test-comp.vue'; export default { name: 'Home', components: { testComp, }, methods: { handleClick(event) { // 觸發事件總線中的事件,並傳參數 this.$bus.$emit('my-click', [1, 2]); }, }, }; </script>
test-comp.vue中訂閱事件總線中的事件
<template> <div class="red"></div> </template> <script> export default { mounted() { // 訂閱事件總線中的事件,並接受參數(要等home.vue的this.$bus.$emit執行后才能執行) this.$bus.$on('my-click', (msg) => { console.log('接受組件home傳來的參數msg: ', msg); }); }, methods: {}, }; </script>