0%

Vue.js 電商練習技術整理 -- event bus 元件間的溝通橋樑

文章目的

在我們開發 Vue 的專案時,每個元件檔案間都會有內外層的差別,例:一個 Root 下有兩個 side 每個 side 底下又有3個元件,當我們需要利用內層的資料來觸發外層的事件時,會需要一層一層的將資料向上傳遞,這會顯得較為麻煩,因此我們可以利用 event bus 的方式,直接將我們內層的資料傳遞給外層作使用。

event bus 簡介

event bus 的重點在於它可以幫我們把特定事件直接掛載到 Vue 的 原型下(Prototype),元件間透過 **$on(監聽)**以及 **$emit(觸發)**兩種行為來達到內層觸發外層事件的效果。

透過 event bus 將內層資料傳遞至外層觸發 alert 效果

新增 alert 模板

我們可以在 Vue Cli 的 components 資料夾底下新增一個 AlertMessage 的元件,並在裡面設計我們的 alert 模板。

將 event bus 掛載到原型上

掛載到原型上的目的是為了讓所有元件皆能使用。
在 Vue Cli 的 src 資料夾底下新增一個 bus.js 並在裡面輸入以下程式碼以完成掛載:

1
2
3
import Vue from 'vue'

Vue.prototype.$bus = new Vue() //$bus 為自訂義的名稱可以自行命名,建議要加上$

接著我們在進入點(main.js)下 import 這隻檔案進來。

1
import './bus'

在 AlertMessage 元件下做監聽

因為我們要讓底層元件觸發 event bus 時, event bus 會將相關資料傳遞到 AlertMessage 做使用,所以我們在 AlertMessage 中加入 event bus 的監聽,程式碼如下:

1
2
3
4
5
6
7
8
9
created () {
const vm = this
// 自定義名稱 'messsage:push'
// message: 傳入參數
// status: 樣式,預設值為 warning
vm.$bus.$on('message:push', (message, status = 'warning') => {
vm.updateMessage(message, status)
})
}

主要監聽時會有幾個屬性與參數可以做設定,自定義的名稱以及監聽的參數,基本上參數就會是內層傳遞上來的資料,接著可以將這些資料參數套用到元件內的其他 methods 中。
像在本次範例中將參數傳遞給 updateMessage 做使用,以下附上完整程式碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
export default {
name: 'Navbar',
data () {
return {
messages: []
}
},
methods: {
updateMessage (message, status) {
const timestamp = Math.floor(new Date() / 1000)
this.messages.push({ //以下3個數值會影響到 alert 顯示結果
message, //alert 顯示的訊息
status, //alert 的顏色
timestamp //alert 的 id
})
this.removeMessageWithTiming(timestamp)
},
//手動關閉 alert
removeMessage (num) {
this.messages.splice(num, 1)
},
//讓訊息顯示後5秒自動消失
removeMessageWithTiming (timestamp) {
const vm = this
setTimeout(() => {
vm.messages.forEach((item, i) => {
if (item.timestamp === timestamp) {
vm.messages.splice(i, 1)
}
})
}, 5000)
}
},
created () {
const vm = this
vm.$bus.$on('message:push', (message, status = 'warning') => {
vm.updateMessage(message, status)
})
}
}

完成 alert 部分的設定後我們可以將此元件 import 進要顯示訊息的 Dashboard 元件下。

1
2
3
4
5
6
import Alert from './AlertMessage'
export default {
components: {
Alert
}
}

要記得將元件加入 HTML 裡。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<template>
<div>
<Navbar/>
<Alert></Alert>
<div class="container-fluid">
<div class="row">
<Sidebar></Sidebar>
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-4">
<router-view></router-view>
</main>
</div>
</div>
</div>
</template>

在內層的 Products 元件上新增 event bus 的觸發事件

透過 ajax 的失敗,觸發 event bus 將相關參數傳遞給 AlertMessage,以下是程式碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  this.$http.post(url, formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
}).then((response) => {
console.log(response.data)
if (response.data.success) {
vm.status.fileUploading = false
vm.$set(vm.tempProduct, 'imageUrl', response.data.imageUrl)
} else {
this.$bus.$emit('message:push', response.data.message, 'danger')
}
})
}

我們在之前 formData 上傳圖片的事件中,新增若上傳失敗就觸發 message:push 並根據我們當初自訂的格式回傳相關參數。
當 AlertMessage 收到我們回傳的參數時,就會根據這些參數去渲染 alert 效果。

小技巧補充

有時候我們在定義 event bus 的事件名稱及相關參數時會忘記是在哪個元件上做定義,因此我們可以利用註解的方式,將我們的定義方法寫在 bus.js 裡以方便了解。
最後,小提醒 event bus 在管理上會有些問題,能的話盡量使用在較不複雜的網頁結構上


參考資料

六角學院課程–Vue 出一個電商網站