非兄弟非父子組件bus通訊踩坑記錄

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ò)的地方,也歡迎指正。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容