前言
組件是 vue.js 最強(qiáng)大的功能之一市俊,而組件實(shí)例的作用域是相互獨(dú)立的铣鹏,這就意味著不同組件之間的數(shù)據(jù)無法相互引用。
如上圖所示刽宪,A 和 B厘贼、B 和 C都是父子關(guān)系,A 和 C 是隔代關(guān)系(可能隔多代)圣拄。針對不同的使用場景嘴秸,如何選擇行之有效的通信方式?
A 組件與 B 組件之間的通信: (父子組件)
如上圖所示庇谆,A岳掐、B、C三個(gè)組件依次嵌套饭耳,按照 Vue 的開發(fā)習(xí)慣串述,父子組件通信可以通過以下三種方式實(shí)現(xiàn):
1、A To B 通過props的方式向子組件傳遞數(shù)據(jù)寞肖,B To A 通過在 B 組件中 $emit, A 組件中 v-on 的方式實(shí)現(xiàn)數(shù)據(jù)傳遞
2纲酗、通過設(shè)置全局Vuex共享狀態(tài),通過 computed 計(jì)算屬性和 commit mutation的方式實(shí)現(xiàn)數(shù)據(jù)的獲取和更新新蟆,以達(dá)到父子組件通信的目的觅赊。
3、Vue Event Bus琼稻,使用Vue的實(shí)例吮螺,實(shí)現(xiàn)事件的監(jiān)聽和發(fā)布,實(shí)現(xiàn)組件之間的傳遞。
往往數(shù)據(jù)在不需要全局的情況而僅僅是父子組件通信時(shí)规脸,使用第一種方式即可滿足坯约。
A 組件與 C 組件之間的通信: (跨多級(jí)的組件嵌套關(guān)系)
如上圖,A 組件與 C 組件之間屬于跨多級(jí)的組件嵌套關(guān)系莫鸭,以往兩者之間如需實(shí)現(xiàn)通信闹丐,往往通過以下方式實(shí)現(xiàn):
- 借助 B 組件的中轉(zhuǎn),從上到下props依次傳遞被因,從下至上卿拴,$emit事件的傳遞,達(dá)到跨級(jí)組件通信的效果
- 借助Vuex的全局狀態(tài)共享
- Vue Event Bus梨与,使用Vue的實(shí)例堕花,實(shí)現(xiàn)事件的監(jiān)聽和發(fā)布,實(shí)現(xiàn)組件之間的傳遞粥鞋。
多級(jí)組件嵌套需要傳遞數(shù)據(jù)時(shí)缘挽,通常使用的方法是通過 vuex。但如果僅僅是傳遞數(shù)據(jù)呻粹,而不做中間處理壕曼,使用 vuex 處理,未免有點(diǎn)大材小用等浊。為此 Vue2.4 版本提供了另一種方法
listeners
attrs/$listeners介紹
$props:當(dāng)前組件接收到的 props 對象腮郊,Vue 實(shí)例代理了對其 props 對象屬性的訪問。
**
attrs" 傳入內(nèi)部組件撒踪。通常配合 interitAttrs 選項(xiàng)一起使用过咬。 通俗的理解為:子輩可以通過$attrs將未在自己組件內(nèi)注冊的祖輩傳遞下來的參數(shù)接收來,并傳遞孫輩制妄。
inheritAttrs:默認(rèn)情況下父作用域的不被認(rèn)作 props 的特性綁定 (attribute bindings) 將會(huì)“回退”且作為普通的 HTML 特性應(yīng)用在子組件的根元素上援奢。通過設(shè)置 inheritAttrs 為 false,這些默認(rèn)行為將會(huì)被去掉忍捡。而通過實(shí)例屬性 $attrs 可以讓這些特性生效,且可以通過 v-bind 顯性的綁定到非根元素上切黔。
**
listeners" 傳入內(nèi)部組件
代碼示例
A組件(index.vue)
<template>
<div>
<h1>我是parent</h1>
<hr>
<child1
:foo="foo"
:boo="boo"
:coo="coo"
:doo="doo"
title="跨級(jí)組件通信"
@test1="test1"
@test2="test2"
></child1>
</div>
</template>
<script>
const child1 = () => import("./child1.vue");
export default {
components: { child1 },
data() {
return {
foo: "foo",
boo: "boo",
coo: "coo",
doo: "doo"
};
},
methods: {
test1() {
alert('test1')
},
test2() {
alert('test2')
}
},
};
</script>
B組件(child1.vue)
<template>
<div>
<h1>我是child1</h1>
<p>props: {{ $props }}</p>
<p>attrs: {{ $attrs }}</p>
<button @click="toParent1()">觸發(fā)test1方法</button>
<hr>
<child2 v-bind="$attrs" v-on="$listeners"></child2>
</div>
</template>
<script>
const child2 = () => import("./child2.vue");
export default {
components: {
child2
},
inheritAttrs: false, // 可以關(guān)閉自動(dòng)掛載到組件根元素上的沒有在props聲明的屬性
props: {
foo: String // foo作為props屬性綁定
},
created() {
console.log(this.$attrs); // { "boo": "boo", "coo": "coo", "doo": "doo", "title": "跨級(jí)組件通信" }
},
methods: {
toParent1() {
this.$emit('test1') // 執(zhí)行test1方法,alert彈框顯示'test1'
}
},
};
</script>
C組件(child2.vue)
<template>
<div class="border">
<h1>我是child2</h1>
<p>props: {{ $props }}</p>
<p>attrs: {{ $attrs }}</p>
<button @click="toParent2">觸發(fā)test2方法</button>
<hr>
<child3 v-bind="$attrs" v-on="$listeners"></child3>
</div>
</template>
<script>
const child3 = () => import("./child3.vue");
export default {
components: {
child3
},
inheritAttrs: false,
props: {
boo: String
},
created() {
console.log(this.$attrs); // { "coo": "coo", "doo": "doo", "title": "跨級(jí)組件通信" }
},
methods: {
toParent2() {
this.$emit('test2') // 執(zhí)行test2方法纬霞,alert彈框顯示'test2'
}
},
};
</script>
D組件(child3.vue)
<template>
<div class="border">
<h1>我是child3</h1>
<p>props: {{ $props }}</p>
<p>attrs: {{ $attrs }}</p>
<button @click="toParent1">觸發(fā)test1方法</button>
<button @click="toParent2">觸發(fā)test2方法</button>
</div>
</template>
<script>
export default {
props: {
coo: String,
title: String
},
methods: {
toParent1() {
this.$emit('test1') // 執(zhí)行test1方法凌埂,alert彈框顯示'test1'
},
toParent2() {
this.$emit('test2') // 執(zhí)行test2方法,alert彈框顯示'test2'
}
},
};
</script>
最終頁面展示效果
總結(jié):
A組件一共傳了四個(gè)變量foo诗芜、boo瞳抓、coo埃疫、doo,一個(gè)屬性title孩哑,兩個(gè)接收函數(shù)test1栓霜,test2
組件B中props中接收了一個(gè)foo。所以$attrs傳的是剩下的 { "boo": "boo", "coo": "coo", "doo": "doo", "title": "跨級(jí)組件通信" }
組件C中props中接收了一個(gè)boo横蜒。所以$attrs傳的是剩下的 { "coo": "coo", "doo": "doo", "title": "跨級(jí)組件通信" }
組件D中props中接收了coo和title胳蛮。所以$attrs傳的是剩下的 { "doo": "doo"}
文章每周持續(xù)更新,可以微信搜索「 前端大集錦 」第一時(shí)間閱讀丛晌,回復(fù)【視頻】【書籍】領(lǐng)取200G視頻資料和30本PDF書籍資料