Vue3中事件總線的具體使用

導讀

在Vue2中,我們遇到復雜的組件通信時,經常采用事件總線的方式來通信。其具體的思路就是實例化一個空白的Vue,並通過其提供的$on$once$emit方法來進行通信。而在Vue3中,上述三個API已經被移除瞭,那麼我們又如何使用事件總線呢?

事件總線的本質

Vue2中的$on$once$emit本質上就是其內部實現瞭一個EventEmitter(事件派發器),每一個事件都和若幹回調相對應,隻要事件被觸發,那麼就將執行此事件所有對應的回調。同時,在JavaScript中,該思想被廣泛地使用,尤其在Node.js的事件機制中,就是創建瞭一個EventEmitter實例,具體請自行查閱相關資料。因此,我們隻需要實現一個簡單的EventEmitter,並全局傳遞到每一個組件中,就可以實現一個事件總線瞭。而全局傳遞,我們可以使用config.globalProperties綁定到每一個組件,也可以在根組件(main)中,通過provide提供總線,需要使用的組件使用inject註入。下面就讓我們來實現一下吧。

構建一個EventEmitter

由於我們可能會有多條總線,我們還是把EventEmitter寫成類的方式,每一條總線都將是一個EventEmitter實例。以下是EventEmitter的簡單實現,其隻實現瞭ononceemit三個API。

class EventEmitter{
    constructor(){
        this.callbacks={};
    }
    on(envetName,callback){
        if(!Array.isArray(this.callbacks[envetName])){
            this.callbacks[envetName]=[];
        }
        this.callbacks[envetName].push(callback);
    }
    emit(eventName,...args){
        if(Array.isArray(this.callbacks[eventName])){
            this.callbacks[eventName].forEach(callback=>callback(...args));
        }
    }
    off(eventName,callback){
        if(!Array.isArray(this.callbacks[eventName])){
            return
        }
        if(callback){
            this.callbacks[eventName].forEach(cb=>{
                if(callback===cb){
                    this.callbacks[eventName].splice(this.callbacks[eventName].indexOf(callback),1);
                }
            });
        } else{
            this.callbacks[eventName]=[];
        }
    }
    once(eventName,callback){
        const that=this;
        const fn=function(){
            callback.apply(that,[...arguments]);
            that.off(eventName,fn);
        }
        that.on(eventName,fn);
    }
}

具體的代碼基本上還是很好理解的,就不在本文解釋瞭,具體請自行查閱相關的資料。

將EventEmitter實例化並全局引入

上文已經說瞭有兩種引入EventEmitter的方法,這裡簡單地給個參考實例吧。

config.globalProperties方法

在main.js中

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
const app=createApp(App);
app.config.globalProperties.$event=new EventEmitter();
app.mount('#app')

在組件中:

//Comp1
<script setup>
import {getCurrentInstance} from "vue"
const vm=getCurrentInstance();
vm.proxy.$event.on('test',()=>{
    console.log('test event emit!')
})
</script>

//Comp2
<script setup>
import {getCurrentInstance} from "vue"
const vm=getCurrentInstance();
vm.proxy.$event.emit('test',"a","b")
</script>

但這種方法不太優雅,不方便定義多條總線,建議使用下述的方法。

provide/inject

在main.js中

provide("eventBus1",new EventEmitter());
provide("eventBus2",new EventEmitter());

在組件中

//Comp1
<script setup>
import {inject} from "vue";
const bus1=inject("eventBus1")
bus1.on("bus1-on-event",()=>{
    console.log('eventBus1 on event emit!')
})
</script>
//Comp2
<script setup>
import {inject} from "vue";
const bus1=inject("eventBus1")
const bus2=inject("eventBus2")
bus2.on("bus2-on-event",()=>{
    console.log('eventBus2 on event emit!')
})
bus1.emit("bus1-on-event")
</script>
//Comp3
<script setup>
import {inject} from "vue";
const bus2=inject("eventBus2")
bus2.emit("bus2-on-event")
</script>

此方法中,使用inject也比使用getCurrentInstance.proxy更優雅一些,且不使用就不必使用inject註入。

結束語

到此這篇關於Vue3中事件總線的具體使用的文章就介紹到這瞭,更多相關Vue3 事件總線內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: