現(xiàn)有3個(gè)嵌套組件脚曾,A->B东且,B->C。 現(xiàn)在我么需要在A中對(duì)C的props賦值本讥,監(jiān)聽C的emit事件
A組件與C組件通信珊泳,我們有多少種解決方案?
1拷沸、我們使用vuex來進(jìn)行數(shù)據(jù)管理色查,依賴于vuex我們可以一次改變,任何一個(gè)組件中都能獲取撞芍。但是如果多個(gè)組件共享狀態(tài)比較少综慎,使用vuex過于麻煩和難以維護(hù)。element-ui中大量采用此方法勤庐。
2示惊、自定義vue bus事件總線,原理類似vuex愉镰,使用特別簡(jiǎn)單米罚。bus適合碰到組件跨級(jí)兄弟組件等無明顯依賴關(guān)系的消息傳遞,原生app開發(fā)中經(jīng)常用到丈探,但是缺點(diǎn)是bus破壞了代碼的鏈?zhǔn)秸{(diào)用录择,大量的濫用將導(dǎo)致邏輯的分散,出現(xiàn)問題后很難定位碗降,降低了代碼可讀性隘竭。
3、使用B來做中轉(zhuǎn)讼渊,A傳遞給B动看,B再給C,這是最容易想到的方案爪幻,但是如果嵌套的組件過多菱皆,需要傳遞的事件和屬性較多须误,會(huì)導(dǎo)致代碼繁瑣,代碼維護(hù)困難仇轻。
對(duì)于我們這種情況京痢,3種方式都有局限性
在vue2.4中,為了解決該需求篷店,引入了listeners祭椰,新增了inheritAttrs選項(xiàng)。我們只需要在B組件中對(duì)引入的C組件增加下面兩個(gè)屬性即可綁定所有的屬性和事件疲陕。
<C v-bind="$attrs" v-on="$listeners"></C>
A組件
<template>
<div>
<h2>組件A 數(shù)據(jù)項(xiàng):{{myData}}</h2>
<B @changeMyData="changeMyData" :myData="myData"></B>
</div>
</template>
<script>
import B from "./B";
export default {
data() {
return {
myData: "100"
};
},
components: { B },
methods: {
changeMyData(val) {
this.myData = val;
}
}
};
</script>
B組件
<template>
<div>
<h3>組件B</h3>
<C v-bind="$attrs" v-on="$listeners"></C>
</div>
</template>
<script>
import C from "./C";
export default {
components: { C },
};
</script>
C組件
<template>
<div>
<h5>組件C</h5>
<input v-model="myc" @input="hInput" />
</div>
</template>
<script>
export default {
props: { myData: { String } },
created() {
this.myc = this.myData; // 在組件A中傳遞過來的屬性
console.info(this.$attrs, this.$listeners);
},
methods: {
hInput() {
this.$emit("changeMyData", this.myc); // // 在組件A中傳遞過來的事件
}
}
};
</script>
實(shí)際應(yīng)用
element-ui開發(fā)的后臺(tái)項(xiàng)目中吭产,大量使用到了el-table和el-pagination做分頁數(shù)據(jù)展示,所以我封裝一個(gè)自定義組件page-table
<template>
<div class="page-table">
<div class="wrapper">
<el-table
ref="elTable"
:data="tableData">
<slot/>
</el-table>
<div style="margin-top: 16px;overflow: hidden">
<el-pagination
class="page"
:current-page="currentPage"
layout="total, prev, pager, next, jumper"
:total="total"
@current-change="handleCurrentChange"/>
</div>
</div>
</div>
</template>
但是這樣做的副作用是引用page-table的地方無法使用el-table和屬性和事件鸭轮。我們?cè)趐age-table中把所有el-table的屬性和事件都中轉(zhuǎn)一遍臣淤?有上百個(gè)呢。
只需在el-table使用的地方加上v-on="attrs"即可窃爷,使用page-table的地方即可使用所有el-table的屬性和事件邑蒋。
<template>
<div class="page-table">
<div class="wrapper">
<el-table
ref="elTable"
v-bind="$attrs"
v-on="$listeners"
:data="tableData">
<slot/>
</el-table>
<div style="margin-top: 16px;overflow: hidden">
<el-pagination
class="page"
:current-page="currentPage"
layout="total, prev, pager, next, jumper"
:total="total"
@current-change="handleCurrentChange"/>
</div>
</div>
</div>
</template>
我們有時(shí)候會(huì)碰到有多個(gè)兄弟組件需要傳遞參數(shù)到最外層,如有B組件包含C1和C2,都需要和A交互按厘,定義2個(gè)props使用v-bind即可
<template>
<div class="page-table">
<div class="wrapper">
<el-table
ref="elTable"
v-bind="table1Props"
:data="tableData">
<slot/>
</el-table>
<el-table
ref="elTable"
v-bind="table2Props"
:data="tableData">
<slot/>
</el-table>
<div style="margin-top: 16px;overflow: hidden">
<el-pagination
class="page"
:current-page="currentPage"
layout="total, prev, pager, next, jumper"
:total="total"
@current-change="handleCurrentChange"/>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
table1Props: Object,
table2Props: Object,
}
</script>