- 2018-06-15創(chuàng)建
組價(jià)通信
vue中一個(gè)比較令人煩惱的事情是屬性只能從父組件傳遞給子組件。這也就意味著當(dāng)你想向嵌套層級(jí)比較深組件數(shù)據(jù)傳遞我碟,只能由父組件傳遞給子組件,子組件再傳遞給孫子組件...
多級(jí)組件嵌套需要傳遞數(shù)據(jù)時(shí)伶唯,通常使用的方法是通過vuex冈敛。如果僅僅是傳遞數(shù)據(jù),而不做中間處理絮记,使用 vuex 處理摔踱,未免有點(diǎn)殺雞用牛刀。Vue 2.4 版本提供了另一種方法怨愤,使用 v-bind=”$attrs”, 將父組件中不被認(rèn)為 props特性綁定的屬性傳入子組件中派敷,通常配合 interitAttrs 選項(xiàng)一起使用。之所以要提到這兩個(gè)屬性撰洗,是因?yàn)閮烧叩某霈F(xiàn)使得組件之間跨組件的通信在不依賴 vuex 和事件總線的情況下變得簡潔篮愉,業(yè)務(wù)清晰。
vm.$attrs
包含了父作用域中不作為 prop 被識(shí)別 (且獲取) 的特性綁定 (class 和 style 除外)差导。當(dāng)一個(gè)組件沒有聲明任何 prop 時(shí)试躏,這里會(huì)包含所有父作用域的綁定 (class 和 style 除外),并且可以通過 v-bind="$attrs" 傳入內(nèi)部組件
示例
<template>
<div class="home">
<mytest :title="title" :massgae="massgae"></mytest>
</div>
</template>
<script>
export default {
name: 'home',
data () {
return {
title:'title1111',
massgae:'message111'
}
},
components:{
'mytest':{
template:`<div>這是個(gè)h1標(biāo)題{{title}}</div>`,
props:['title'],
data(){
return{
mag:'111'
}
},
created:function(){
console.log(this.$attrs)//注意這里
}
}
}
}
</script>
上邊的代碼设褐,我們?cè)诮M件里只是用了title這個(gè)屬性颠蕴,massgae屬性我么是沒有用的,那么下瀏覽器渲染出來是什么樣呢络断?如下圖:
我們看到:組件內(nèi)未被注冊(cè)的屬性將作為普通html元素屬性被渲染裁替,如果想讓屬性能夠向下傳遞,即使prop組件沒有被使用貌笨,你也需要在組件上注冊(cè)。這樣做會(huì)使組件預(yù)期功能變得模糊不清襟沮,同時(shí)也難以維護(hù)組件的DRY锥惋。在Vue2.4.0,可以在組件定義中添加inheritAttrs:false昌腰,組件將不會(huì)把未被注冊(cè)的props呈現(xiàn)為普通的HTML屬性。但是在組件里我們可以通過其$attrs可以獲取到?jīng)]有使用的注冊(cè)屬性膀跌,如果需要鸦泳,我們?cè)谶@也可以往下繼續(xù)傳遞日月。
components:{
'mytest':{
template:`<div>這是個(gè)h1標(biāo)題{{title}}</div>`,
props:['title'],
inheritAttrs: false,
data(){
return{
mag:'111'
}
},
created:function(){
console.log(this.$attrs)//注意這里
}
}
繼續(xù)
$attrs
包含了父作用域中不被認(rèn)為 (且不預(yù)期為) props 的特性綁定 (class 和 style 除外)。當(dāng)一個(gè)組件沒有聲明任何 props 時(shí),這里會(huì)包含所有父作用域的綁定 (class 和 style 除外)肯腕,并且可以通過 v-bind=”$attrs” 傳入內(nèi)部組件——在創(chuàng)建更高層次的組件時(shí)非常有用。
$listeners
包含了父作用域中的 (不含 .native 修飾器的) v-on 事件監(jiān)聽器否纬。它可以通過 v-on=”$listeners” 傳入內(nèi)部組件——在創(chuàng)建更高層次的組件時(shí)非常有用盖袭。
inheritAttrs
默認(rèn)情況下父作用域的不被認(rèn)作 props 的特性綁定 (attribute bindings) 將會(huì)“回退”且作為普通的 HTML 特性應(yīng)用在子組件的根元素上。當(dāng)撰寫包裹一個(gè)目標(biāo)元素或另一個(gè)組件的組件時(shí)熄诡,這可能不會(huì)總是符合預(yù)期行為可很。通過設(shè)置 inheritAttrs 到 false,這些默認(rèn)行為將會(huì)被去掉凰浮。而通過 (同樣是 2.4 新增的) 實(shí)例屬性 $attrs 可以讓這些特性生效我抠,且可以通過 v-bind 顯性的綁定到非根元素上。
上述特性的使用完全可以降低在不使用Vuex以及事件總線的情況下袜茧,組件跨級(jí)props以及事件傳遞的復(fù)雜度菜拓。
完整示例
$attrs以及$listeners的出現(xiàn)解決的就是第一種情況的問題,B 組件在其中傳遞props以及事件的過程中笛厦,不必在寫多余的代碼纳鼎,僅僅是將$attrs以及$listeners向上或者向下傳遞即可。
A組件(App.vue)
<template>
<div id="app">
<child1
:p-child1="child1"
:p-child2="child2"
v-on:test1="onTest1" //此處監(jiān)聽了兩個(gè)事件递递,可以在B組件或者C組件中直接觸發(fā)
v-on:test2="onTest2">
</child1>
</div>
</template>
<script>
import Child1 from './Child1.vue';
export default {
data () {
return {};
},
components: { Child1 },
methods: {
onTest1 () {
console.log('test1 running...');
},
onTest2 () {
console.log('test2 running');
}
}
};
</script>
B組件(Child1.vue)
<template>
<div class="child-1">
<p>in child1:</p>
<p>props: {{pChild1}}</p>
<p>$attrs: {{$attrs}}</p>
<hr>
<!-- C組件中能直接觸發(fā)test的原因在于 B組件調(diào)用C組件時(shí) 使用 v-on 綁定了$listeners 屬性 -->
<!-- 通過v-bind 綁定$attrs屬性喷橙,C組件可以直接獲取到A組件中傳遞下來的props(除了B組件中props聲明的) -->
<child2 v-bind="$attrs" v-on="$listeners"></child2>
</div>
</template>
<script>
import Child2 from './Child2.vue';
export default {
props: ['pChild1'],
data () {
return {};
},
inheritAttrs: false,
components: { Child2 },
mounted () {
this.$emit('test1');
}
};
</script>
結(jié)果:
in child1:
props: v_child1
$attrs: { “p-child2”: “v_child2”}
C 組件 (Child2.vue)
<template>
<div class="child-2">
<p>in child2:</p>
<p>props: {{pChild2}}</p>
<p>$attrs: {{$attrs}}</p>
<hr>
</div>
</template>
<script>
export default {
props: ['pChild2'],
data () {
return {};
},
inheritAttrs: false,
mounted () {
this.$emit('test2');
}
};
</script>
結(jié)果:
in child2:
props: v_child2
$attrs: {}
其他
<template>
<component
:is="type"
v-bind="vbinds"
@getValue="(v) => getValue(v, i)"
/>
</template>
<script>
export default {
data () {
return {
vbinds: {
ismultiple: '',
region: '',
logic: ''
}
};
},
};
</script>