在之前的文章中我們提到了vue常用的幾種通信方式,如父子,子父,以及兄弟組件之間的通信,可以通過這個傳送門了解他們:Vue通信方式(一)
當我們如果遇到祖組件,父組件,孫組件,三個級別嵌套時,我們該怎么在祖組件與孫組件之間通信呢,當然通過本地存儲或者Vuex都可以實現,但僅僅是一個值得時候未免有點小題大做了,或者是組件之間的通信那樣一級一級傳?有點麻煩,在此,我們就詳解如何實現祖孫之間的通信。
首先我們來看看vue新增的兩個屬性:$attrs和$listeners,這是vue2.4新增的兩個屬性,我們來看看官方文檔是怎么解釋的吧。
好吧,對於第一次看的童鞋來說,並不知道他在BB什么, 簡要的講就是,$attrs可以獲取父作用域傳入的值(不包括props中的),$listeners相當於父作用域的事件監聽器,那我們就可以用這兩個屬性實現祖孫之間的數據通信
首先,我們定義一個祖級別的組件:father1.vue
<template>
<h6>父組件:
<p>這是來自c組件的數據:{{msg1}}</p>
<div>
<B :messagec="messagec" :msgc="msgc2" v-on:getCData="getCData"></B>
</div>
</h6>
</template>
<script>
import B from './son.vue'
export default{
data() {
return {
messagec:{a:1,c:2}, //傳遞給c組件的數據,可以傳對象,字符串以及其他類型
msg:'',
msg1:'',
msgc2:'第二個傳給孫組件的值'
}
},
components:{
B
},
methods:{
//執行C子組件觸發的事件
getCData(val){
console.log("這是來自C組件的數據:"+val)
this.msg1=val
}
}
}
</script>
然后在定義一個父級別的組件:son.vue,相當於祖孫通信之間的中間件
<template>
<h1>這是子組件:
<div>
<p>這是B組件</p>
<!-- C組件中能直接觸發getCData的原因在於 B組件調用C組件時 使用 v-on 綁定了$listeners 屬性 -->
<!-- 通過v-bind 綁定$attrs屬性,C組件可以直接獲取到A組件中傳遞下來的props(除了B組件中props聲明的) -->
<C v-bind="$attrs" v-on="$listeners"></C>
</div>
</h1>
</template>
<script>
import C from './c.vue' // 引入C組件
export default{
data(){
return {
mymessage:''
}
},
components:{
C
},
props:{
// messagec:String // 當在這個組件聲明了傳向C組件的值時,C組件則通過$attrs.messagec得不到該值,相當於被攔截了,要傳給C,則不能在此聲明
},
methods:{
}
}
</script>
主要是綁定兩個屬性v-bind="$attrs" v-on="$listeners",並且不能在props中聲明傳入的值,"$attrs"用於接受father.vue傳入的值,$listeners用於監聽觸發事件傳值給father.vue.
最后我們定義一個孫級別的組件:c.vue
<template>
<h1>這是C組件:
<p>接受來自father的值:{{$attrs.messagec.a}}</p>
<p>接受來自father第二個的值:{{$attrs.msgc}}</p>
<input type="text" v-model="msgtofather" @input="passCData(msgtofather)">
</h1>
</template>
<script>
export default{
data(){
return{
msgtofather:'' //傳給father組件的值
}
},
props:{
// messagec:String // 當在這個組件聲明了傳向C組件的值時,C組件則通過$attrs.messagec得不到該值,相當於被攔截了,要傳給C,則不能在此聲明
},
methods:{
passCData(val){
//觸發父組件father中的事件
this.$emit('getCData',val)
}
}
}
</script>
注意:此組件中props也不能聲明父組件傳入的值,否則$attrs.messagec.a會取不到該值,並且可以接受多個來自祖組件的值
最后,組件通信的測試圖如下:

