之前我們實現了子組件向父組件傳遞數據,很明顯,這是不夠的,看完這篇博客,無論哪兩個組件之間傳遞和接收數據都沒有問題!
全局事件總線(適用於任意組件間通信) 原理:(看圖理解)
主要就是通過往 x 身上放事件,然后事件的回調要放在想要獲取數據的組件身上,誰要傳數據就調用 x 身上對應的事件並往里面存數據就可以了,相當於一個中間商(哎,不得不說,它一出生就被利用了)
當然不是誰都能但此大任的,x 需要具備兩個條件:
-
所有組件都可以看到
-
x 身上有 on、on 、on、off 、$emit 方法
統一給 x 命名為 $bus
我們將其定義在 main.js 文件中,創建在 vm 的實例對象身上,因為 vm 實例對象只有一個
創建全局事件總線有兩種方法:
1、
const Demo = Vue.extend({})
const d = new Demo()
Vue.prototype.$bus = d
(定義在創建 Vue 的外面)
2、
new Vue({
......
beforeCreate(){
Vue.prototype.$bus = this //安裝全局事件總線, $bus 就是當前應用的 vm
},
})
復制代碼
new Vue({
render: h => h(App),
beforeCreate(){
Vue.prototype.$bus = this //安裝全局事件總線
}
}).$mount('#app')
復制代碼
使用事件總線:
- 接收數據:A 組件想接收數據,則在 A 組件中給 $bus 綁定自定義事件,事件的回調留在 A 組件自身
mounted() { //或者后面指向的是一個方法,方法在 methods 里面定義 //在全局事件總線 bus中綁定一個hello事件,后面的回調是箭頭函數,用於接收數據this.bus 中綁定一個 hello 事件,后面的回調是箭頭函數,用於接收數據 this.bus中綁定一個hello事件,后面的回調是箭頭函數,用於接收數據this.bus.$on("hello", (value) => { console.log("我獲取到了數據", value); }); },
- 提供數據:
methods: { sentMyName(){ //在該方法中觸發 hello 這個事件,把數據傳過去 this.bus.bus.bus.emit('hello',this.myName) } }, 用這個方法的好處就是!我們就不需要再在標簽里綁定自定義事件了,直接把事件在 $bus 里創建,再在要傳數據的地方調用它就可以了!
當然還有個注意點,如果某個事件或綁定事件的組件你不用了,那要養成隨時解綁的好習慣!不要占着空間不用,會導致空間浪費從而出現卡頓
最好在 beforeDestroy 鈎子中,用 $off 去解綁當前組件所用到的事件
在綁定事件的組件中解綁(即需要數據的組件)
beforeDestroy() { //解綁 bus中名為hello的事件this.bus 中 名為 hello 的事件 this.bus中名為hello的事件this.bus.off("hello"); }, 切記!this.bus.off()里面一定要寫要解綁的事件,不然off() 里面一定要寫要解綁的事件,不然 off()里面一定要寫要解綁的事件,不然bus 中所有的事件都會被解綁!后果很嚴重!!!!
消息訂閱與發布(適用於任意組件間通信) 原理:
簡單理解:
需要數據的組件:訂閱消息 提供數據的組件:發布消息
這個相比第一種方法就要麻煩那么一丟丟了,它需要安裝 pubsub,我們打開 VScode 的控制台,輸入 npm i pubsub-js,進行安裝
在傳數據和接收數據的組件中都要通過 import pubsub from 'pubsub-js' 引入這個文件
然后就可以開始使用了
接收數據:A 組件想接收數據,則在 A 組件中訂閱消息,訂閱的回調留在 A 組件自身
this.pubId = pubsub.subscribe('hello',(msgName,data)=>{
console.log('我接收到數據了',data);
})
復制代碼
這里有一個注意點,那就是回調函數的第一個參數 msgName,代表的是 hello,即訂閱的消息名,這個必須要寫,因為默認第一個參數就是消息名,第二個參數才是數據,前端培訓所以不管如何,第一個要占個位,你可以給它取個名字,或者用下划線 _ 占位
提供數據:
methods: { sentMyName(){ pubsub.publish('hello',this.myName) } }, 當然如果訂閱的消息不用了,也要將其刪除,不能占用空間,但是刪除訂閱消息不是用 $off ,而是 publish.unsubscribe(this.pubId),其中 this.pubId 是每個消息創建的時候都會有一個 id,就像定時器一樣,我們刪除就刪除它對應的 id 號就可以了
beforeDestroy() { pubsub.unsubscribe(this.pubId) }, 對比兩者我們用的更多的是前者,因為它是 Vm 里面創建的,不需要再導入包
最后再分享一個方法: