Vue祖孫組件如何實(shí)現(xiàn)傳值
先看基礎(chǔ)
祖孫組件,也就是 3 層嵌套的組件。關(guān)于 vue 中父子組件之間的數(shù)據(jù)傳遞是通過(guò) props 和 $emit 實(shí)現(xiàn),參考 Vue 父子組件傳值。
那祖孫組件之間傳值怎么實(shí)現(xiàn),先了解下面的幾個(gè) vue 屬性。
$props
當(dāng)前組件接收到的 props 對(duì)象。Vue 實(shí)例代理了對(duì)其 props 對(duì)象 property 的訪問(wèn)。
$attrs
$attrs 是一個(gè) Object,它包含了父作用域中不作為 prop 被識(shí)別 (且獲取) 的 attribute 綁定 (class 和 style 除外)。
如果組件沒(méi)有聲明任何 prop 時(shí),這里會(huì)包含所有父作用域的綁定 (class 和 style 除外),并且可以通過(guò) v-bind="$attrs" 傳入內(nèi)部組件。
怎么理解呢?
就是父組件綁定到子組件上的屬性,在子組件中沒(méi)有聲明 props 進(jìn)行接收的那些屬性會(huì)被包含在 attrs 中,舉個(gè)栗子
在父組件中對(duì)子組件綁定了兩個(gè)屬性 data1 data2。
parent.vue
<Child :data1="data1" :data2="data2" />
<script>
import Child from './child'
...
data(){
return{
data1: 'String',
data2: ['String','Array']
}
}
...
</script>
但在子組件的 props 只對(duì) data1 做了接收聲明,那 data2 就會(huì)被包含在 $attrs 中。
在子組件中也是可以取到 $attrs 的值的,既然是對(duì)象,那就還可以按照屬性名來(lái)取值的。
child.vue
<template>
<div>
<div>$attrs: {{ $attrs }}</div>
<div>data2: {{ $attrs['data2'] }}</div>
</div>
</template>
<script>
...
props: ['data1'], /* <--看這里,只對(duì)data1做接收聲明 */
data(){
return{...}
}
...
</script>

其實(shí)到這里還沒(méi)有結(jié)束,接著聊聊 inheritAttrs 吧。不過(guò)這和傳值之間關(guān)系不大。
inheritAttrs 是 vue 2.4.0 的新增選項(xiàng),官方的介紹是醬紫的。
1?? 默認(rèn)情況下父作用域的不被認(rèn)作 props 的 attribute 綁定 (attribute bindings) 將會(huì)“回退”且作為普通的 HTML attribute 應(yīng)用在子組件的根元素上。當(dāng)撰寫(xiě)包裹一個(gè)目標(biāo)元素或另一個(gè)組件的組件時(shí),這可能不會(huì)總是符合預(yù)期行為。通過(guò)設(shè)置 inheritAttrs 到 false,這些默認(rèn)行為將會(huì)被去掉。
2?? 而通過(guò) (同樣是 2.4 新增的) 實(shí)例 property $attrs 可以讓這些 attribute 生效,且可以通過(guò) v-bind 顯性的綁定到非根元素上。
?? 注意:這個(gè)選項(xiàng)不影響 class 和 style 綁定。
第1??簡(jiǎn)單理解就是前面說(shuō)的,在子組件中的 props 沒(méi)有聲明接收的屬性(也就是 $attrs 所包含的屬性)會(huì)被綁定到這個(gè)子組件的 HTML 根節(jié)點(diǎn)上,我們檢查代碼也是可以看到的。
就像下面的例子,來(lái)自父組件的消息沒(méi)有被接收時(shí)會(huì)作為屬性被渲染到子組件的根節(jié)點(diǎn)上。

然后是使用 inheritAttrs: false 可以避免被渲染。
第2??說(shuō)的就是可以通過(guò) v-bind="$attrs" 把這些屬性綁定到其他的節(jié)點(diǎn)上(包括子節(jié)點(diǎn),這是祖孫組件傳值的技術(shù)基礎(chǔ))
$listeners
vue 2.4.0 新增
$listeners 是個(gè) Object。包含了父作用域中的 (不含 .native 修飾器的) v-on 事件監(jiān)聽(tīng)器。它可以通過(guò) v-on="$listeners" 傳入內(nèi)部組件。
祖?zhèn)鲗O
在 vue 中,祖孫組件之間是不能直接通信的,需要通過(guò)父組件作為 中間組件。
實(shí)際上祖父的關(guān)系就是兩個(gè) 父與子 的關(guān)系。
1. $props 鏈
【不推薦使用】
既然是兩個(gè)父與子之間的關(guān)系,那就可以 祖?zhèn)鞲?/strong> 再由 父?jìng)髯?/strong>。而 props 可以用來(lái)接收來(lái)自父組件的值,那就可以通過(guò) props 實(shí)現(xiàn)鏈?zhǔn)絺鬟f了。不舉栗子??了,舉個(gè)香蕉吧??。
傳遞次序:GrandFather → Father → GrandSon
① 在 GrandFather 中給 Father 傳遞了兩條消息。
GrandFather.vue
<template>
<div class="parent">
??爺爺
<Father :msg1="msg1" :msg2="msg2" />
</div>
</template>
<script>
import Father from './Father'
export default {
components: {Father},
data () {
return {
msg1: '1??我是GrandFather,把第二條傳給GrandSon',
msg2: '2??GrandSon你好,我是GrandFather'
}
}
}
</script>
② Father 中使用 props 接收了來(lái)自 GrandFather 的所有消息。是的,他把所有的消息都收下了而且還可以隨便看??。
當(dāng)然,使用 props 鏈傳遞就必須要 Father 接收之后才能繼續(xù)傳遞。
看完消息之后,Father 按照 GrandFather 的意思,把 msg2 傳遞給了 GrandSon
Father.vue
<template>
<div class="parent">
??父親
<p>GrandFather說(shuō):{{msg1}}。{{msg2}}</p>
<GrandSon :msg2="msg2" />
</div>
</template>
<script>
import GrandSon from './GrandSon'
export default {
props: ['msg1', 'msg2'],
components: {GrandSon},
}
</script>
③ 終于到 GrandSon 了,它通過(guò) props 從 Father 那里接收到了來(lái)自 GrandFather 的消息。
GrandSon.vue
<template>
<div class="child">
??孫子
<p>GrandFather說(shuō):{{msg2}}</p>
</div>
</template>
<script>
export default {
props: ['msg2']
}
</script>

小結(jié)
這種方式雖然是比較容易理解,但也是比較繁瑣的。中間組件需要接收所有的 props 等。
2. $attrs
上面的 $props 傳值方式必須要經(jīng)過(guò) Father 接收之后繼續(xù)傳遞,也是個(gè)缺點(diǎn),畢竟 Father 還是很忙的,要負(fù)責(zé)自己的功能,不能總為爺孫倆接傳消息??。
vue 在 2.4.0 版本中新增了 $attrs 屬性。根據(jù)前面的理解 $attrs 就是沒(méi)有在 props 中聲明要接收的一些屬性。此外,還可以通過(guò) v-bind="$attrs" 把來(lái)自父組件的一些屬性直接傳遞到子組件中。
這樣一來(lái),Father 組件就沒(méi)必要在 props 中聲明接收那些不必要屬性了??纯磳?shí)例吧!
① GrandFather 組件不用做修改
② 這次在 Father 中只在 props 接收了 msg1,與自己無(wú)關(guān)的直接使用 v-bind="attrs" 綁定到子組件上。
當(dāng)然,在 Father 中還是可以訪問(wèn) $attrs 的。在代碼中訪問(wèn)要使用 this.$attrs
Father.vue
<template>
<div class="parent">
??父親
<p>$attrs:{{$attrs}}</p>
<GrandSon v-bind="$attrs" />
</div>
</template>
<script>
import GrandSon from './GrandSon'
export default {
props: ['msg1'], //只接收了msg1
components: {GrandSon},
}
</script>
③ 子組件也不需要做修改

在 Father 中接收了 msg1,所以在 Father 中繼續(xù)傳遞到 GrandSon 的就只有 msg2 了。
孫傳祖
$listeners
給 Father 組件綁定 自定義事件 getReply ,便于后面在 GrandSon 中觸發(fā)
GrandFather.vue
<template>
<div class="parent">
??爺爺
<div>GrandSon的回復(fù):{{reply}}</div>
<Father :msg1="msg1" :msg2="msg2" @getReply="getReply"/>
</div>
</template>
<script>
import Father from './Father'
export default {
components: {Father},
data () {
return {
msg1: '1??我是GrandFather,把第二條傳給GrandSon',
msg2: '2??GrandSon你好,我是GrandFather',
reply: '' //接收來(lái)自GrandSon的消息
}
},
methods: {
/* 將獲得的數(shù)據(jù)綁定到data中,便于視圖層渲染 */
getReply (param) {
this.reply = param
}
}
}
</script>
在 Father 中使用 v-on="$listeners" 把 GrandFather 的事件綁定到 GrandSon
Father.vue
<template>
<div class="parent">
??父親
<p>$attrs:{{$attrs}}</p>
<GrandSon v-bind="$attrs" v-on="$listeners" />
</div>
</template>
<script>
import GrandSon from './GrandSon'
export default {
props: ['msg1'],
components: { GrandSon },
}
</script>
在 GrandSon 中觸發(fā)來(lái)自 GrandFather 的自定義事件就 ?? 了,有兩種方式。
① this.$listeners.eventName(param)
② this.$emit(eventName, param)
GrandSon.vue
<template>
<div class="child">
??孫子
<p>GrandFather說(shuō):{{msg2}}</p>
<button @click="reply">回復(fù)GrandFather</button>
</div>
</template>
<script>
export default {
props: ['msg2'],
data () {
return {
replyWord: 'GrandFather你好,我是GrandSon,收到消息了'
}
},
methods: {
reply () {
this.$emit('getReply', this.replyWord)
// this.$listeners.getReply(this.replyWord)
}
}
}
</script>

總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
vue+d3js+fastapi實(shí)現(xiàn)天氣柱狀圖折線圖餅圖的示例
本文主要介紹了vue+d3js+fastapi實(shí)現(xiàn)天氣柱狀圖折線圖餅圖的示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2025-04-04
Vue Router實(shí)現(xiàn)多層嵌套路由的導(dǎo)航的詳細(xì)指南
在 Vue 應(yīng)用中,使用 Vue Router 可以輕松實(shí)現(xiàn)多層嵌套路由的導(dǎo)航,嵌套路由允許你創(chuàng)建一個(gè)多層次的 URL 結(jié)構(gòu),這在構(gòu)建具有復(fù)雜導(dǎo)航結(jié)構(gòu)的應(yīng)用程序時(shí)非常有用,需要的朋友可以參考下2024-10-10
vue內(nèi)置組件component--通過(guò)is屬性動(dòng)態(tài)渲染組件操作
這篇文章主要介紹了vue內(nèi)置組件component--通過(guò)is屬性動(dòng)態(tài)渲染組件操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-07-07
vue組件中使用props傳遞數(shù)據(jù)的實(shí)例詳解
這篇文章主要介紹了vue組件中使用props傳遞數(shù)據(jù)的實(shí)例詳解,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2018-04-04
vue3+Naive?UI數(shù)據(jù)表格基本使用方式詳解
這篇文章主要給大家介紹了關(guān)于vue3+Naive?UI數(shù)據(jù)表格基本使用方式詳?shù)南嚓P(guān)資料,Naive?UI是一個(gè)基于Typescript開(kāi)發(fā)的針對(duì)Vue3開(kāi)發(fā)的UI組件庫(kù),由TuSimple(圖森未來(lái))公司開(kāi)發(fā)并開(kāi)源,需要的朋友可以參考下2023-08-08
element?ui中el-form-item的屬性rules的用法示例小結(jié)
這篇文章主要介紹了element?ui中el-form-item的屬性rules的用法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧2024-07-07
vue中的@click.native 原生點(diǎn)擊事件
這篇文章主要介紹了vue中的@click.native 原生點(diǎn)擊事件,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04

