vue中非父子組件的通信你瞭解嗎
我們總結瞭父子組件通信方式有:props
+ emit
。這裡我們將總結一下,非父子組件通信方式,這裡還不涉及到Vuex。
如果存在祖孫組件,我們可以通過Provide
和Inject
進行通信。
如果不是祖孫組件,也不是父子組件,我們可以采用Mitt全局事件總線
第三方庫來實現。
一、Provide和Inject
Provide
和Inject
用於非父子組件之間共享數據,比如有一些深度嵌套的組件,子組件想要獲取父組件的數據,如果不存在Provide和Inject選項,我們可以通過props進行一次傳遞數據,但是這樣做太過於繁瑣。
對於上述情況,我們可以使用Provide
和Inject
無論組件結構嵌套有多深,父組件都可以作為子組件數據的提供者。
父組件存在Provide
來提供數據。
子組件存在Inject
來獲取數據。
在實際過程中,父組件不知道哪個子組件使用其數據,子組件也不知道使用的是哪個父組件的數據。
Provide和Inject的基本使用
//父組件 <template> <div> <Content></Content> </div> </template> <script> import Content from "./components/Content.vue"; export default { data() { return {}; }, provide:{ name:"張三", age:20 }, components: { Content } }; </script> <style scoped></style>
//子組件 <template> <div> <h1>這裡是Content組件</h1> <h1>{{ name }} -- {{age}}</h1> <ContentBase></ContentBase> </div> </template> <script> import ContentBase from "./ContentBase.vue"; export default { data() { return {}; }, components: { ContentBase }, inject:["name", "age"] }; </script> <style scoped></style>
//孫組件 <template> <div> <h1>這裡是contentBase組件</h1> <h1>{{name}} -- {{age}}</h1> </div> </template> <script> export default { data() { return {}; }, inject: ["name", "age"] }; </script> <style scoped> </style>
最終顯示結果為:
二、Provide和Inject的另一種寫法
我們思考一種情況,如果Provide
拿到的數據,是從data
拿到的數據,此時如果獲取? 此時this
可以使用嗎?
<template> <div> <Content></Content> </div> </template> <script> import Content from "./components/Content.vue"; export default { data() { return { source: ["111","222", "333"] }; }, provide:{ name:"張三", age:20, res: this.source.length //我們在此時增加res,想要通過this.source.length拿到數組的長度 }, components: { Content } }; </script> <style scoped></style>
該結果是錯誤的。
報錯信息顯示,我們從undefined上讀取屬性,此時this為undefined。原因:從上面代碼我們可以看出,this指向的是undefiend(因為this執行最外層)。
解決方法
我們將Provide設置為一個函數,並且返回一個對象,如下代碼所示:
<template> <div> <Content></Content> </div> </template> <script> import Content from "./components/Content.vue"; export default { data() { return { source: ["111", "222", "333"], }; }, provide() { return { name: "張三", age: 20, res: this.source.length, }; }, components: { Content, }, }; </script> <style scoped></style>
顯示結果:
此時我們再思考一個問題,如果我們向data數組中新增一個元素,在其他地方獲取的數組長度會跟隨變化嗎?
<template> <div> <Content></Content> <button @click="addOneItem">點擊</button> </div> </template> <script> import Content from "./components/Content.vue"; export default { data() { return { source: ["111", "222", "333"], }; }, provide() { return { name: "張三", age: 20, res: this.source.length, }; }, components: { Content, }, methods:{ //在這裡添加點擊事件 addOneItem() { this.source.push("nnn") console.log(this.source) } } }; </script> <style scoped></style>
結果如上圖所示,可以看到數據是被添加進去的,但是子組件並沒有檢測到數據的變化。
此時我們可以使用computed
來檢測this.source.length
的變化,使用代碼如下所示。
<template> <div> <Content></Content> <button @click="addOneItem">點擊</button> </div> </template> <script> import Content from "./components/Content.vue"; import { computed } from "vue" //從vue中引入computed export default { data() { return { source: ["111", "222", "333"], }; }, provide() { return { name: "張三", age: 20, res: computed(() => this.source.length), //在這裡添加computed }; }, components: { Content, }, methods:{ addOneItem() { this.source.push("nnn") console.log(this.source) } } }; </script> <style scoped></style>
因為我們通過computed
獲取的是一個對象,此時我們通過value
屬性拿到值。
三、全局事件總線mitt庫
在vue2時,如果我們使用事件總線可以使用this.$bus = new Vue()也就是實例化一個vue對象。但是我們在vue3中不能這樣用。所以我們采用第三方庫來實現組件之間的通信。這個第三方庫為mitt
一、安裝
npm install mitt
在文件中引入並且進行初始化導出。
import mitt from "mitt"; const emitter = new mitt() export default emitter
監聽事件,第一個參數是事件名,第二個參數是回調函數。
emitter.on("why", (data) => { console.log(data) }) //*表示可以監聽全部的事件。 emitter.on("*", (type, data) => { console.log(type, data) })
取消事件
//取消emitter中所有的監聽 emitter.all.clear() //或者 //定義一個函數 function onFoo(){} emitter.on("foo", onFoo) emitter.on("foo", onFoo)
總結
本篇文章就到這裡瞭,希望能夠給你帶來幫助,也希望您能夠多多關註WalkonNet的更多內容!
推薦閱讀:
- vue3 非父子組件通信詳解
- Vue3.x使用mitt.js進行組件通信
- vue3中 provide 和 inject 用法及原理
- vue3組件通信的方式總結及實例用法
- vue前端開發層次嵌套組件的通信詳解