Vue祖孫組件如何實現(xiàn)傳值
先看基礎(chǔ)
祖孫組件,也就是 3
層嵌套的組件。關(guān)于 vue
中父子組件之間的數(shù)據(jù)傳遞是通過 props
和 $emit
實現(xiàn),參考 Vue 父子組件傳值。
那祖孫組件之間傳值怎么實現(xiàn),先了解下面的幾個 vue
屬性。
$props
當(dāng)前組件接收到的 props
對象。Vue 實例代理了對其 props
對象 property
的訪問。
$attrs
$attrs
是一個 Object
,它包含了父作用域中不作為 prop
被識別 (且獲取) 的 attribute
綁定 (class
和 style
除外)。
如果組件沒有聲明任何 prop
時,這里會包含所有父作用域的綁定 (class
和 style
除外),并且可以通過 v-bind="$attrs"
傳入內(nèi)部組件。
怎么理解呢?
就是父組件綁定到子組件上的屬性,在子組件中沒有聲明 props
進(jìn)行接收的那些屬性會被包含在 attrs
中,舉個栗子
在父組件中對子組件綁定了兩個屬性 data1
data2
。
parent.vue
<Child :data1="data1" :data2="data2" /> <script> import Child from './child' ... data(){ return{ data1: 'String', data2: ['String','Array'] } } ... </script>
但在子組件的 props
只對 data1
做了接收聲明,那 data2
就會被包含在 $attrs
中。
在子組件中也是可以取到 $attrs
的值的,既然是對象,那就還可以按照屬性名來取值的。
child.vue
<template> <div> <div>$attrs: {{ $attrs }}</div> <div>data2: {{ $attrs['data2'] }}</div> </div> </template> <script> ... props: ['data1'], /* <--看這里,只對data1做接收聲明 */ data(){ return{...} } ... </script>
其實到這里還沒有結(jié)束,接著聊聊 inheritAttrs
吧。不過這和傳值之間關(guān)系不大。
inheritAttrs
是 vue 2.4.0
的新增選項,官方的介紹是醬紫的。
1?? 默認(rèn)情況下父作用域的不被認(rèn)作 props
的 attribute
綁定 (attribute bindings
) 將會“回退”且作為普通的 HTML attribute
應(yīng)用在子組件的根元素上。當(dāng)撰寫包裹一個目標(biāo)元素或另一個組件的組件時,這可能不會總是符合預(yù)期行為。通過設(shè)置 inheritAttrs
到 false
,這些默認(rèn)行為將會被去掉。
2?? 而通過 (同樣是 2.4 新增的) 實例 property $attrs
可以讓這些 attribute
生效,且可以通過 v-bind
顯性的綁定到非根元素上。
?? 注意:這個選項不影響 class
和 style
綁定。
第1??簡單理解就是前面說的,在子組件中的 props
沒有聲明接收的屬性(也就是 $attrs
所包含的屬性)會被綁定到這個子組件的 HTML
根節(jié)點(diǎn)上,我們檢查代碼也是可以看到的。
就像下面的例子,來自父組件的消息沒有被接收時會作為屬性被渲染到子組件的根節(jié)點(diǎn)上。
然后是使用 inheritAttrs: false
可以避免被渲染。
第2??說的就是可以通過 v-bind="$attrs"
把這些屬性綁定到其他的節(jié)點(diǎn)上(包括子節(jié)點(diǎn),這是祖孫組件傳值的技術(shù)基礎(chǔ))
$listeners
vue 2.4.0
新增
$listeners
是個 Object
。包含了父作用域中的 (不含 .native
修飾器的) v-on
事件監(jiān)聽器。它可以通過 v-on="$listeners"
傳入內(nèi)部組件。
祖?zhèn)鲗O
在 vue
中,祖孫組件之間是不能直接通信的,需要通過父組件作為 中間組件。
實際上祖父的關(guān)系就是兩個 父與子 的關(guān)系。
1. $props 鏈
【不推薦使用】
既然是兩個父與子之間的關(guān)系,那就可以 祖?zhèn)鞲?/strong> 再由 父傳子。而 props 可以用來接收來自父組件的值,那就可以通過 props 實現(xiàn)鏈?zhǔn)絺鬟f了。不舉栗子??了,舉個香蕉吧??。
傳遞次序: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
接收了來自 GrandFather
的所有消息。是的,他把所有的消息都收下了而且還可以隨便看??。
當(dāng)然,使用 props
鏈傳遞就必須要 Father
接收之后才能繼續(xù)傳遞。
看完消息之后,Father
按照 GrandFather
的意思,把 msg2
傳遞給了 GrandSon
Father.vue
<template> <div class="parent"> ??父親 <p>GrandFather說:{{msg1}}。{{msg2}}</p> <GrandSon :msg2="msg2" /> </div> </template> <script> import GrandSon from './GrandSon' export default { props: ['msg1', 'msg2'], components: {GrandSon}, } </script>
③ 終于到 GrandSon
了,它通過 props
從 Father
那里接收到了來自 GrandFather
的消息。
GrandSon.vue
<template> <div class="child"> ??孫子 <p>GrandFather說:{{msg2}}</p> </div> </template> <script> export default { props: ['msg2'] } </script>
小結(jié)
這種方式雖然是比較容易理解,但也是比較繁瑣的。中間組件需要接收所有的 props
等。
2. $attrs
上面的 $props
傳值方式必須要經(jīng)過 Father
接收之后繼續(xù)傳遞,也是個缺點(diǎn),畢竟 Father
還是很忙的,要負(fù)責(zé)自己的功能,不能總為爺孫倆接傳消息??。
vue
在 2.4.0
版本中新增了 $attrs
屬性。根據(jù)前面的理解 $attrs
就是沒有在 props
中聲明要接收的一些屬性。此外,還可以通過 v-bind="$attrs"
把來自父組件的一些屬性直接傳遞到子組件中。
這樣一來,Father
組件就沒必要在 props
中聲明接收那些不必要屬性了??纯磳嵗?!
① GrandFather
組件不用做修改
② 這次在 Father
中只在 props
接收了 msg1
,與自己無關(guān)的直接使用 v-bind="attrs"
綁定到子組件上。
當(dāng)然,在 Father
中還是可以訪問 $attrs
的。在代碼中訪問要使用 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: '' //接收來自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ā)來自 GrandFather
的自定義事件就 ?? 了,有兩種方式。
① this.$listeners.eventName(param)
② this.$emit(eventName, param)
GrandSon.vue
<template> <div class="child"> ??孫子 <p>GrandFather說:{{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é)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
antd vue 如何調(diào)整checkbox默認(rèn)樣式
這篇文章主要介紹了antd vue 如何調(diào)整checkbox默認(rèn)樣式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-12-12如何解決element-ui動態(tài)加載級聯(lián)選擇器默認(rèn)選中問題
這篇文章主要介紹了如何解決element-ui動態(tài)加載級聯(lián)選擇器默認(rèn)選中問題,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的朋友可以參考一下2022-09-09element-ui中table組件的toggleRowSelection()方法使用
這篇文章主要介紹了element-ui中table組件的toggleRowSelection()方法使用,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-03-03