Vue_Eventbus元件橋樑

使用時機

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

一般常用的父、子層組件溝通,會使用 props 、 $emit 來傳收資料;可是多個組件需要共用一種狀態時,就會需要使用到全域狀態管理的 Vuex。可是有時候情況只是兄、弟層組件溝通,沒有那麼複雜需要用到 Vuex ,就可以使用 EventBus。

元件如何掛載?又如何彼此溝通?

元件用法又分為兩種,一種只是圖型呈現,就只需要搭載至主頁面中就可以,另一種是需要呼叫主頁面裡的變數、函式,就需要用到emit及props呼叫,bus也是同一類型。

  1. 第一種元件:單純呈現template
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

<template>
<div>
<Navbar/>
</div>
</template>

<script>
import Navbar from './Navbar'

export default {
components:{
Navbar,
}}
</script>
  1. 第二種元件:需使用主頁面的變數及函式

變數使用props,函式使用emit,除了跟上圖一樣啟用載入元件路徑之外,還需要在載入對應的變數及函數(如下圖),例如:頁籤

1
<Pagination :A="pagination" @B="getProducts" ></Pagination>
  1. 第三種元件:當觸發事件後,在元件內會進行函式運算

無須啟用圖一的載入元件路徑,只需在接口處註冊新增bus.on(自定義名稱A)

1
2
3
4
5
6
7
8
9

created() {
this.getCart();
const vm = this;

vm.$bus.$on('updateCart',()=>{
vm.getCart();
});
},

並再主頁面點擊某種物件時,同時觸發元件A內容,使用bus.emit當作接口回傳至元件內部執行函式裡的內容即可,例如:彈跳提示視窗、包含動態式購物車也要(另需template增加<>項目)。

1
2
3
this.$http.post(api, cart).then((res) => {
vm.$bus.$emit('updateCart');
this.$bus.$emit('message:push',res.data.message,'success')

EventBus簡介

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

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

初始化

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

第一種,直接在 main.js 檔案中初始化,目的是要在 Vue 的原型下掛載 EventBus。

1
2
//main.js
Vue.prototype.$EventBus = new Vue();

第二種,新增一個 eventBus.js 檔案,在其中引入 Vue,並且匯出宣告出來的 Vue 實例。實際上,它是一個不具有 DOM 元素的組件,它僅有 Vue 實例的方法,因此非常輕便。

1
2
3
4
// eventBus.js

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

掛載 EventBus

全域掛載:將 eventBus 加入 root實例中的 data 中,讓每個子組件都能夠使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

//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),
});

發送事件

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

//xxx.vue

<script>
// ...略
methods:{
testFunc(){
this.$EventBus.$emit("testEvent",{
title:"Test Event Title",
message:"This is test event."
});
}
}
// ...略
</script>

接收事件

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

//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>

統整

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