vue匯流排bus傳值的一些問題

来源:https://www.cnblogs.com/ljh-dream/archive/2018/12/01/10048291.html
-Advertisement-
Play Games

動態組件中用匯流排Bus的坑 在我們的項目總難免會遇到用動態組件,這裡就拿 "vue官方的例子" 為例,我們欲在組件中添加匯流排bus(其實官方推薦的vuex更好用,但是有時候我們只需要傳一個小狀態,不需要用vuex),首先要mian.js 中創建一個匯流排Bus(當然這裡一般要把Bus封裝一下放在一個單 ...


動態組件中用匯流排Bus的坑

在我們的項目總難免會遇到用動態組件,這裡就拿vue官方的例子為例,我們欲在組件中添加匯流排bus(其實官方推薦的vuex更好用,但是有時候我們只需要傳一個小狀態,不需要用vuex),首先要mian.js 中創建一個匯流排Bus(當然這裡一般要把Bus封裝一下放在一個單獨的js中,這裡單純只是為了演示,就在main.js中創建一個全局的EventBus)

import Vue from 'vue'
import App from './App'
import router from './router'

window.EventBus = new Vue()
/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

然後我們在動態組件Tabhome中寫個按鈕觸發emit事件,在觸發的時候把我們想要傳的值一併帶過去。

<template>
<div>
  <div>
    <button @click="handleClick">觸發</button>
  </div>
</div>
</template>

<script>
export default {
  name: 'TabHome',
  data () {
    return {
      msg: 'home data  '
    }
  },
  methods: {
    handleClick () {
      window.EventBus.$emit('getData', this.msg)
    }
  }

}
</script>

然後我們在我們想在接受值的地方監聽觸發的這個函數,我這裡拿TabPosts來監聽Tabhome中觸發的函數,註意這兩個組件是動態組件,不是通過路由切換的,監聽組件如下:

<template>
<div>
  {{post}}
</div>
</template>

<script>
export default {
  name: 'TabPosts',
  data () {
    return {
      post: 'tabposts',
    }
  },
  methods: {
    getData (msg) {
      this.post = msg
    }
  },
  mounted () {
      window.EventBus.$on('getData', (msg) => this.getData(msg))
  }
}
</script>

我們期望的結果當然是我們在tabhome中點擊了按鈕之後,當我們切換到TabPosts組件的時候,TabPosts中的值已經發生了改變,也就是從tabhome中傳過來的值,但是情況遠非我們想的這麼簡單,在監聽函數中添加console你就會發現,第一次點擊按鈕,並切換到TabPosts組件的時候,不會列印任何東西,也就是沒有觸發mounted鉤子。當你切回去tabhome組件再次點擊按鈕,然後再回到TabPosts組件,發現控制台有輸出,但是隨著來回切換次數的增多,控制台每次列印的數量也會隨著你切換的次數一次遞增,但是數據發生了改變,視圖卻沒有改變。
這是為什麼呢?這就是動態組件的坑,因為我用的是生命周期的鉤子函數,監聽函數要在觸發函數之前存在 ,不然當然監聽不到了。問題就出在生命周期函數這裡。所以我們來在兩個組件中加上所有的生命周期鉤子併在裡面輸出識別信息。tabhome組件如下:

<template>
<div>
  <div>
    <button @click="handleClick">觸發</button>
  </div>
</div>
</template>

<script>
export default {
  name: 'TabHome',
  data () {
    return {
      msg: 'home data  '
    }
  },
  methods: {
    handleClick () {
      window.EventBus.$emit('getData', this.msg)
    }
  },
  beforeCreate () {
    console.log('A beforecreate')
  },
  created () {
    console.log('A created')
  },
  beforeMount () {
    console.log('A beforemount')
  },
  mounted () {
    console.log('A mounted')
  },
  beforeUpdate () {
    console.log('A before update')
  },
  updated () {
    console.log('A updated')
  },
  beforeDestroy () {
    console.log('A before destroy')
  },
  destroyed () {
    console.log('A beforecreate')
  }

}
</script>

TabPosts組件如下(為了在控制台明顯區分,在這裡給TabPost組件列印的東西加上黃色的背景色):

<template>
<div>
  {{post}}
  <router-link to="/TabHome">return</router-link>
</div>
</template>

<script>
export default {
  name: 'TabPosts',
  data () {
    return {
      post: 'tabposts',
      number: 0
    }
  },
  methods: {
    getData (msg) {
      this.post = msg
    }
  },
  beforeCreate () {
    console.log('%c%s',
      'background: yellow;',
      'B beforecreate')
  },
  created () {
    console.log('%c%s',
      'background: yellow;',
      'B created')
  },
  beforeMount () {
    console.log('%c%s',
      'background: yellow;',
      'B beforemount')
  },
  mounted () {
    console.log('%c%s',
      'background: yellow;',
      'B mounted')
      window.EventBus.$on('getData', (msg) => this.getData(msg))
  },
  beforeUpdate () {
    console.log('%c%s',
      'background: yellow;',
      'B before update')
  },
  updated () {
    console.log('%c%s',
      'background: yellow;',
      'B updated')
  },
  beforeDestroy () {
    console.log('%c%s',
      'background: yellow;',
      'B before destroy')
  },
  destroyed () {
    console.log('%c%s',
      'background: yellow;',
      'B beforecreate!')
  }
}
</script>

<style scoped>

</style>

然後我們測試從動態組件tabhome到TabPosts組件的這個過程中控制台會列印出什麼,結果如下圖:

我們會發現,A組件(即是tabhome組件)和B組件(即是TabPosts組件)兩個的生命周期函數沒有交集也就是說觸發emit的時候並沒有監聽到,所以視圖不會改變。至於在動態組件中來回切換會增加觸發次數,根據前人的經驗,應該是在監聽組件B中的beforeDestroy中添加EventBus.$off函數就好了,但是會發下加了這個off之後,就不會觸發$on的監聽函數了,至於為什麼不會監聽函數這其中的原因我也不太懂。
目前還沒找到動態組件中實現匯流排Bus的好方法,大佬們有好方法歡迎指正!

組件之間的Bus匯流排傳值

因為動態組件之間的坑,我放棄了用動態組件,改用路由切換的兩個組件進行傳值。在路由的index.js中加入路由信息

import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/pages/Home'
import TabHome from '@/pages/Dynamic-component/components/TabHome'
import TabPosts from '@/pages/Dynamic-component/components/TabPosts'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Home',
      component: Home
    }, {
      path: '/tabhome',
      name: 'TabHome',
      component: TabHome
    }, {
      path: '/TabPosts',
      name: 'TabPosts',
      component: TabPosts
    }
  ]
})

但是這其中也有坑,我們由A(即tabhome)組件觸發EventBus.$emit 函數,讓B(即TabPosts)組件監聽EventBus.$on,一般觸發函數都會放到click函數中,也就是哪個事件需要就放到哪裡,本例子放到click事件中。監聽函數一般放到created或者mounted中,這裡我放到了mounted中。
A(tabhome)組件代碼如下:

<template>
<div>
  <div>
    <button @click="handleClick">觸發</button>
  </div>
</div>
</template>

<script>
export default {
  name: 'TabHome',
  data () {
    return {
      msg: 'home data  '
    }
  },
  methods: {
    handleClick () {
      window.EventBus.$emit('getData', this.msg)
      this.$router.push('/TabPosts')
    }
  },
  beforeCreate () {
    console.log('A beforecreate')
  },
  created () {
    console.log('A created')
  },
  beforeMount () {
    console.log('A beforemount')
  },
  mounted () {
    console.log('A mounted')
  },
  beforeUpdate () {
    console.log('A before update')
  },
  updated () {
    console.log('A updated')
  },
  beforeDestroy () {
    console.log('A before destroy')
  },
  destroyed () {
    console.log('A beforecreate')
  }
}
</script>

B(TabPosts)組件的代碼如下:

<template>
<div>
  {{post}}
  <router-link to="/TabHome">返回</router-link>
</div>
</template>

<script>
export default {
  name: 'TabPosts',
  data () {
    return {
      post: 'tabposts',
      number: 0
    }
  },
  methods: {
    getData (msg) {
      this.post = msg
    }
  },
  beforeCreate () {
    console.log('%c%s',
      'background: yellow;',
      'B beforecreate')
  },
  created () {
    console.log('%c%s',
      'background: yellow;',
      'B created')
  },
  beforeMount () {
    console.log('%c%s',
      'background: yellow;',
      'B beforemount')
  },
  mounted () {
    console.log('%c%s',
      'background: yellow;',
      'B mounted')
       window.EventBus.$on('getData', (msg) => this.getData(msg))
  },
  beforeUpdate () {
    console.log('%c%s',
      'background: yellow;',
      'B before update')
  },
  updated () {
    console.log('%c%s',
      'background: yellow;',
      'B updated')
  },
  beforeDestroy () {
    console.log('%c%s',
      'background: yellow;',
      'B before destroy')
  },
  destroyed () {
    console.log('%c%s',
      'background: yellow;',
      'B beforecreate!')
  }
}
</script>

<style scoped>

</style>

結果我們按照這個代碼運行總是不成功,沒有我們想要的效果,上面的代碼我加了所有的生命周期的鉤子函數,我們從A的按鈕切換到B組件,註意留意控制台,當我們點擊按鈕通通過路由切換到B組件的時候,生命周期函數的變化,我們會發現如下的結果。

我們發現,在A銷毀之前,B組件的beforeCreate ,created,和beforeMount這三個鉤子函數先觸發,之後才是A組件的銷毀鉤子的觸發,因為匯流排Bus要求要先有監聽在觸發,才能成功監聽,所以我們只能在A組件的beforeDestroy或者destroyed這兩個生命周期鉤子中觸發函數$emit,同理也只能在B組中的beforeCreate ,created,和beforeMount這三個鉤子函數中監聽$on。

//tabhome (A)組件中在beforeDestroy中觸發
beforeDestroy () {
    console.log('A before destroy')
    window.EventBus.$emit('getData', this.msg)
  }
//在TabPosts中的created中監聽
created () {
    console.log('%c%s',
      'background: yellow;',
      'B created')
      console.log(1)
    window.EventBus.$on('getData', (msg) => this.getData(msg))
  }

這樣我們想要的功能就實現了,實際動手做的細心的同學會發現:還是有之前重覆觸發的問題,還是會隨著切換次數的增加而使監聽函數觸發的次數增加,解決這個問題就簡單了。在我們用匯流排傳值的時候要記得關閉監聽,在B組件中的destroyed鉤子中增加EventBus.$off方法即可,至此就沒問題了。

//TabPosts組件
 destroyed () {
    console.log('%c%s',
      'background: yellow;',
      'B beforecreate!')
    window.EventBus.$off('getData')
  }

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 什麼是屬性選擇器 指對帶有指定屬性的HTML元素設置樣式,有以下幾種: 1.element[attribute] 2.element[attribute = "value"] 3.element[attribute ~= "value"] 4.element[attribute ^= "value" ...
  • 一般用於公告的滾動效果 ...
  • chalk 是一個可以給終端輸出加上色彩的工具包,有了它,你的終端將變得五顏六色,花哨的一匹
  • Class constructor() 實例對象 表達式 提升 私有方法和私有屬性 this name屬性 取值函數和存值函數 Generator方法 靜態方法 靜態屬性和實例屬性 new.target屬性 1.constructor是構造方法。 2.this關鍵字則代表實例對象。 3.定義“類”的 ...
  • 1. dom>documentElement>body>tagname 2.我們常用的節點標簽。 元素節點(標簽) 文本節點 屬性節點(標簽里的屬性) 3.document有個屬性nodeType返回的是數字 1.代表元素節點 2.代表屬性節點 3.代表文本節點 4.節點的獲取 元素節點獲取有很多方 ...
  • 話不多說,直接開魯 1. startsWith() 作用: 檢測字元串以什麼開頭 實例: 2. endsWith() 作用: 檢測字元串以什麼結尾 實例: 3. includes() 作用: 檢測字字元串中是否包含某個字元 實例: 4. repeat(n) 作用: 重覆 n 次 實例 5. padS ...
  • 接下去一系列關於 JavaScript 語法的文章中,將會出現很多在 Java 里出現或者沒出現過的專業術語,所以第一篇就先來羅列一下,每個術語先給一定的解釋。 有的理解不了沒關係,等這系列文章看完,再回過頭來看這一張基本也都能理解了。先羅列出來,至少有個印象,不至於到時看到一臉懵逼。 ...
  • 前言   本文主要介紹facebook推出的一個類庫immutable.js,以及如何將immutable.js集成到我們團隊現有的react+redux架構的移動端項目中。 本文較長(5000字左右),建議閱讀時間: 20 min 通過閱讀本文,你可以學習到: 什麼是immut ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...