FBI Warning:本文是記錄本菜鳥學(xué)習(xí)bus通信的一次記錄。如大佬熟練掌握Vue或已對(duì)Vue源碼有了解,不建議浪費(fèi)時(shí)間閱讀。部分文字可能引起感官上的不適,請(qǐng)?jiān)谀?女朋友的陪同下閱讀
1.整體思路
看了官網(wǎng)文檔關(guān)于bus的用法,遂想寫個(gè)簡單的組件bus通訊demo練手。
- showTime組件監(jiān)聽bus的自定義事件,并對(duì)傳遞的參數(shù)做處理
- getTime組件通過bus觸發(fā)自定義事件
2. 相關(guān)代碼
上面的思路對(duì)應(yīng)代碼如下。為方便直接用vue-cli構(gòu)建
2.1 showTime.vue
<template>
<div >
<p>時(shí)間:{{time}}</p>
</div>
</template>
<script>
import bus from './bus'
export default {
data () {
return {
time: '初始值'
}
},
created() {
bus.$on('get', data => {
console.log(data)
this.time= data
})
}
}
</script>
2.2 getTime.vue
<template>
<div>
<p>我是組件b</p>
<button @click="getTime">發(fā)送時(shí)間給組件a</button>
</div>
</template>
<script>
import bus from './bus'
export default {
methods: {
getTime() {
bus.$emit('get', `${new Date()}`)
}
}
}
</script>
2.3 bus.js
import Vue from 'vue'
export default new Vue()
2.4 路由
import Vue from 'vue'
import Router from 'vue-router'
import getTime from '@/components/getTime '
import showTime from '@/components/showTime'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
component: showTime
},
{
path: '/getTime',
component: getTime
}
]
})
3. 出現(xiàn)問題
3.1 操作步驟
- 先進(jìn)入showTime組件,讓bus開始監(jiān)聽自定義的事件
- 然后進(jìn)入getTime組件,通過點(diǎn)擊按鈕觸發(fā)事件
- 理想情況下,再次進(jìn)入showTime組件,會(huì)更新time的值,并更新視圖
3.2 問題概述
- showTime組件視圖并沒有如期更新
- 多次重復(fù)以上步驟,第n次進(jìn)入后點(diǎn)擊按鈕,會(huì)執(zhí)行n次
console.log(data)
4. debug思路
- 通過觀察,發(fā)現(xiàn)bus的get事件在getTime組件的按鈕按下后,在觸發(fā)bus的get事件時(shí)就已經(jīng)將參數(shù)
new Date()發(fā)送出去了,而非進(jìn)入showTime組件時(shí)。 - 這個(gè)現(xiàn)象糾正了我之前對(duì)bus通訊一個(gè)錯(cuò)誤的認(rèn)識(shí):之前我以為bus是在進(jìn)入showTime的created鉤子時(shí),才會(huì)響應(yīng)get事件并傳遞參數(shù)。事實(shí)是,showTime組件只是提供了為 bus 注冊(cè)事件的時(shí)機(jī)。一旦注冊(cè),在組件層面上 bus 已經(jīng)跟showTime組件沒關(guān)系了。
- 3.1的三個(gè)操作步驟,實(shí)質(zhì)上發(fā)生了以下事情:
- bus開始監(jiān)聽get事件
- showTime組件銷毀。在getTime組件bus觸發(fā)get事件,傳遞參數(shù)
new Date()。 - getTime組件銷毀,在created鉤子,time值初始化為'初始值'(這一步中,get事件傳遞參數(shù)的時(shí)機(jī)早于getTime組件的created鉤子,所以視圖不會(huì)更新);同時(shí)bus再次監(jiān)聽一個(gè)新的get事件(為什么會(huì)說再次呢?接下來會(huì)解釋)
- 關(guān)于上文提到的bus再次監(jiān)聽一個(gè)新的事件,我們先將showTime組件的created鉤子添加調(diào)試代碼,
通過觀察bus._events的變化來理解
bus.$on('get', data => {
console.log(data)
this.time= data
})
console.log(bus._events) //
- bus._events是一個(gè)對(duì)象。當(dāng)進(jìn)入showTime的created鉤子,會(huì)為bus._events添加一個(gè)key為get,value為空數(shù)組,并將監(jiān)聽get事件的回調(diào)函數(shù)添加至這個(gè)數(shù)組。因此,n次進(jìn)入showTime組件后,這個(gè)數(shù)組就會(huì)添加n個(gè)回調(diào)函數(shù)。每一次在getTime組件按下按鈕,都會(huì)執(zhí)行數(shù)組里的每一個(gè)回調(diào)函數(shù),造成n次切換路由后點(diǎn)擊按鈕,bus監(jiān)聽自定義函數(shù)的代碼會(huì)被執(zhí)行n遍
5. 解決方案
- 從上面的分析中可以看出,出現(xiàn)的2個(gè)問題都是和組件的created鉤子有關(guān)。所以可以通過使用
keep-alive緩存組件,除了第一次進(jìn)入showTime組件會(huì)觸發(fā)created生命周期,之后切換路由都不會(huì)銷毀組件。因此之后進(jìn)入showTime組件,time都會(huì)被更新為傳遞的參數(shù),也不會(huì)往bus._events添加多個(gè)自定義事件回調(diào)函數(shù) - 但感覺這樣似乎有點(diǎn)復(fù)雜,如果對(duì)于非兄弟非父子組件的Bus通訊有更好的用法,更深的理解,歡迎一起探討。水平有限,如文章有說錯(cuò)的地方,也歡迎指正。