vue組件間通信的一些實用方法(VUE2.x)
一、父子組件間通信
- 常用的父子組件通信方法,一般涉及props和$emit之間的交互,也就是我們在vue常說的屬性傳遞和事件映射,實例如下:
<template>
<div class="parent">
<child :message="message" @getReply="getReply"></child>
</div>
</template>
<script>
import child from './child'
export default {
name: 'parent',
components:{
child
},
data() {
return {
message: '你好'
}
},
methods:{
getReply(message){
console.log('子組件回復(fù)消息',message);
}
}
}
</script>
<template>
<div class="child">
</div>
</template>
<script>
export default {
name: 'child',
props:['message'],
mounted(){
//如果接收到父組件傳遞的消息,進行消息回復(fù)
if(this.props.message){
this.$emit('getReply','已收到消息');
}
}
}
</script>
說明:上訴代碼中,父組件和子組件在同一文件夾之下,父組件引用并使用了child子組件,并利用message傳遞給子組件一句“你好”。子組件在mounted生命周期獲取屬性message,如果獲取到消息,利用"getReply"事件映射,告訴父組件已收到消息,父組件通過綁定事件的getReply方法進行接收。這就是一個常用的vue父子間通過屬性和事件進行通信的過程。
-
子組件調(diào)用父組件的方法,父組件調(diào)用子組件的方法
-
子組件調(diào)用父組件方法,常用的應(yīng)用場景例如,父組件為一個表格組件,子組件是表單修改或保存的模態(tài)框組件,子組件填寫表單完成后點擊保存,請求成功后需要刷新表格組件。代碼示例如下:
<!--父組件(表格組件)--> <template> <div class="table"> <dialog></dialog> </div> </template> <script> import dialog from './dialog' export default { name: 'table', components:{ dialog }, provide() { return { refreshTableData: this.getData, } }, methods:{ getData(){ //表格獲取請求數(shù)據(jù)的方法,由于只是簡單的示例,所以就不寫實際業(yè)務(wù)代碼了 } } } </script> <!--子組件(表單模態(tài)框)--> <template> <div class="dialog"> <!--子組件--> <button @click="save">保存</button> </div> </template> <script> export default { name: 'dialog', inject: ['refreshTableData'], methods:{ save(){ /*當(dāng)針對表格進行新增或修改操作后,打開模態(tài)框針對表單填寫完畢后進行保存 * 這時候通過異步請求數(shù)據(jù)保存成功后,需要父組件的表格數(shù)據(jù)刷新 * 就可通過父組件提供的refreshTableData方法進行操作 * */ this.refreshTableData(); } } } </script>
說明:通過provider和inject提供了子組件調(diào)用父組件的函數(shù)方法,不僅限于函數(shù)方法,也可通過此方法調(diào)用父組件的變量。
-
-
父組件調(diào)用子組件的方法和變量的方法相對簡單,可通過ref獲取子組件的實例進行調(diào)用,不過一般不建議這樣使用,相對不太規(guī)范,但是也是一個可行性方案。代碼如下:
<template> <div class="parent"> <child ref="child"></child> </div> </template> <script> import child from './child' export default { name: 'parent', components:{ child }, methods:{ useChildMethod(){ this.$refs.child.init(); } } } </script>
說明:假設(shè)子組件內(nèi)部有一個init的初始化方法,可在父組件通過ref獲取組件實例進行調(diào)用。
二、全局組件間的通信
-
利于vuex建立全局的數(shù)據(jù)共享
全局通信一般的業(yè)務(wù)場景可能是功能菜單、面包屑、頁面之間的聯(lián)動操作,或者購物APP的購物車效果。我們簡單舉例購物車效果的實際應(yīng)用。代碼如下:
// shoppingBag.js文件 const shoppingBag = { state: { goods:[] }, mutations: { // 設(shè)置一級菜單 SET_GOODS: (state, goods) => { state.goods = goods }, }, actions: { setGoods({commit}, goods) { commit('SET_GOODS',goods) }, } }; export default shoppingBag
上面簡單的作為一個購物車的store模塊,里面定義了goods變量存放商品,提供了一個setGoods方法用于保存商品數(shù)據(jù)。由于只是舉例演示,并沒有書寫真實的業(yè)務(wù)復(fù)雜代碼。真實場景可能是設(shè)計商品名稱、id、數(shù)量等信息,涉及購物車入庫時的相關(guān)商品數(shù)據(jù)處理,這邊不做贅述。
為了在組件文件中使用goods變量,需要定義getters:
//新建一個getters.js文件,聲明getters const getters = { goods: state => state.shoppingBag.goods, }; export default getters
定義store的使用:
// store.js文件 import Vue from 'vue' import Vuex from 'vuex' import shoppingBag from './shoppingBag' import getters from './getters' Vue.use(Vuex); const store = new Vuex.Store({ modules: { shoppingBag, }, getters }); export default store
然后在vue項目的入口文件中需要在vue實例中使用我們聲明的store,示例如下:
import Vue from 'vue' import router from './router' import store from './store' new Vue({ el: '#app', router, store, template: '<App/>', })
然后我們就可以在全局任何一個組件中用mapGetters在計算屬性中去獲取goods變量并使用,通過store的dispatch方法去觸發(fā)購物車的setGoods方法,更新購物車數(shù)據(jù):
import {mapGetters} from 'vuex'; export default { name:'test-component', computed: { ...mapGetters([ 'goods' ]), }, methods:{ //更新購物車數(shù)據(jù) updateGoods(){ let data = [];//新的購物車數(shù)據(jù) this.$store.dispatch('setGoods',data); } } }
以上就是通過vuex實現(xiàn)全局組件間數(shù)據(jù)通信的一個簡單流程介紹。
-
通過vue實例的事件映射和事件監(jiān)聽達到全局通信的效果:
大家都知道父子組件通信時我們可以通過綁定事件監(jiān)聽,和子組件通過$emit事件映射,可以達到子組件到父組件的一個通信過程,利用這個方法,我們可以實現(xiàn)全局的一個事件的通信。示例如下:
// 在main.js入口文件中聲明一個broadcast廣播示例,綁定在vue的原型上方便我們?nèi)质褂?Vue.prototype.$broadcast = new Vue(); //在項目中示例一個發(fā)送廣播的組件 export default { name:'send-message', mounted(){ //在mounted生命周期發(fā)送一條廣播 this.$broadcast.$emit('contact','你好'); } } //在項目中示例一個發(fā)送廣播的組件 export default { name:'get-message', destroyed() { this.$bus.$off('contact', this.getMessage); }, mounted(){ //在mounted生命周期進行監(jiān)聽 this.$broadcast.$on('contact',this.getMessage); }, methods:{ getMessage(message){ //收到消息做相關(guān)的業(yè)務(wù)處理 } } }
說明:通過
$emit
發(fā)送廣播事件時,進行相應(yīng)監(jiān)聽的組件都會收到消息并觸發(fā)綁定的函數(shù)方法。在這邊,我在組件的destoryed生命周期對綁定函數(shù)進行了解綁,如果不解綁的話,由于事件隊列相同事件名稱的綁定函數(shù)是一個數(shù)組,就算組件被銷毀,但是$broadcast這個實例未銷毀,在上面綁定的事件函數(shù)就是冗余的,會影響js代碼性能,所以在組件被銷毀后需及時進行解綁,否則可能會造成一些不可預(yù)料的系統(tǒng)bug。(此處“broadcast”只是一個命名,大家可以根據(jù)自己需要進行命名,常用的命名方式可能使用“bus”。盡量不要使用broadcast,可能會與vue內(nèi)置的一些屬性方法沖突)