Vue-EventBus組件溝通

使用情境

在 Vue 框架的核心概念中,會盡可能將資料數據與 UI 封裝成可重複使用的組件,然而,當涉及組件與組件之間的資料交互傳輸時,就需要用到組件溝通的工具。

一般常用的父、子層組件溝通,會使用 props 、 $emit 來傳收資料;可是多個組件需要共用一種狀態時,就會需要使用到全域狀態管理的 Vuex。

可是有時候情況只是兄、弟層組件溝通,沒有那麼複雜需要用到 Vuex ,就可以使用 EventBus。

參考延伸說明: Props使用方式Props/)、Vuex使用時機%E7%8B%80%E6%85%8B%E7%AE%A1%E7%90%86vuex(1:2)/)

EventBus簡介

在 Vue 中使用 EventBus,就像是所有組件共同的事件中心,組件與組件之間可以上下垂直、左右平行互相溝通。

具體做法是在專案入口檔案,建立一個 Vue 實例(Instance) 作為 EventBus,接著在各個組件之中去引入這個 EventBus,透過分別調用 EventBus 的事件監聽來完成組件之間的資料傳遞。

實作

初始化 EventBus

首先要創建一個 EventBus,有兩種方式:

  1. 第一種,直接在 main.js 檔案中初始化,目的是要在 Vue 的原型下掛載 EventBus。
1
2
//main.js
Vue.prototype.$EventBus = new Vue();
  1. 第二種,新增一個 eventBus.js 檔案,在其中引入 Vue,並且匯出宣告出來的 Vue 實例。實際上,它是一個不具有 DOM 元素的組件,它僅有 Vue 實例的方法,因此非常輕便。
    1
    2
    3
    4
    // eventBus.js

    import Vue from "vue";
    export const EventBus = new Vue();

掛載 EventBus

  1. 如果使用第一種初始化,是直接在 Vue 的原型下掛載 EventBus,所以在初始化 EventBus 時就同步完成全域掛載了。

    1
    Vue.prototype.$EventBus = new Vue();
  2. 若使用第二種方法初始化,獨立宣告並創建出 EventBus 之後,接下來就要在欲使用它的地方掛載它,分為全域級區域掛載。

  • 全域掛載:將 eventBus 加入 root實例中的 data 中,讓每個子組件都能夠使用。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    //main.js
    import Vue from "vue";
    import eventBus from "./eventBus.js";

    export default new Vue({
    store, //use store
    i18n,
    el: '#app',
    data: {
    EventBus:eventBus,
    },
    methods: {},
    render: (h) => h(app),
    });
  • 區域掛載:也可以在欲使用的組件中個別引入 eventBus
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//xxx.vue
<template>
// ...略
</template>
<script>
import {EventBus} from ./eventBus.js;
export default{
name:"testComponent",
data(){
return{
// ...略
}
}
}
</script>
<style>
// ...略
</style>

發送事件

  • 全域 EventBuse:如果是全域掛載的 EventBus 可以在任意組件中,利用 $EventBus 取得 EventBus,再呼叫 $emit 送出事件並傳遞資料。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    //xxx.vue

    <script>
    // ...略
    methods:{
    testFunc(){
    this.$EventBus.$emit("testEvent",{
    title:"Test Event Title",
    message:"This is test event."
    });
    }
    }
    // ...略
    </script>
  • 區域 EventBuse:因為非全域,所以僅在欲使用的組件中去引入,並使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//xxx.vue

<script>
import {EventBus} from ./eventBus.js;
export default{
name:"testComponent",
data(){
return{
title:"Test Event Title",
message:"This is test event.",
}
},
methods:{
testFunc(){
EventBus.$emit("testEvent",{
title:this.title,
message:this.message
});
}
}
}
</script>

接收事件

  • 全域 EventBuse:可以在任一組件中利用 $on 去監聽,只要監聽事件被觸發,都可以接收到訊息。如果想移除事件的監聽,則使用 $off 不需要添加其他任何參數。

    記得在組件銷毀之前(beforeDestroy),清除監聽事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//xxx.vue

<script>
// ...略
export default{
name:"xxx",
created(){
this.$EventBus.$on("testFunc",event=>{
console.log("Title:"+event.title);
console.log("Msg:"+event.message);
})
},
beforeDestroy(){
this.$EventBus.$off("testFunc");
}
}
// ...略
</script>
  • 區域 EventBuse:在欲使用的組件中去引入 EventBuse,一樣使用 $on 去監聽、使用 $off移除事件監聽
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//xxx.vue

<script>
import {EventBus} from ./eventBus.js;
export default{
name:"testComponent",
data(){
return{
title:"Test Event Title",
message:"This is test event.",
}
},
mounted:{
EventBus.$on("testFunc",{title,message}=>{
console.log("Title:"+title);
console.log("Msg:"+message);
})
},
beforeDestroy:{
EventBus.$off("testFunc");
}
}
</script>

總結

EventBus 身為一個全域的實例,所有的組件都透過 $emit 方法向 EventBus 傳送、更新資料;而其他所有的組件,也同步使用監聽事件 $on 偵測它有沒有發生變化,一但資料數據發生變化,就會獲取 event 其中的資料數據

© 2020 Leah's Blog All Rights Reserved. 本站访客数人次 本站总访问量
Theme by hiero