参考: vue父、子、孙组件间数据传递、事件传递 - 掘金 (juejin.cn)
方式一. 利用$attrs实现祖孙组件间的数据传递,$listeners实现祖孙组件间的事件监听
$attrs包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件——在创建高级别的组件时非常有用。
$listeners包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。
例:
爷组件:
<div>
<my-mask :show="isShow" :title="title" :con="con" @on-submit="submit"></my-mask>
</div>
... ...
components: {
myMask, // 子组件
},
data() {
return {
isShow: false,
title: '我是标题',
con: '我是内容',
};
},
methods: {
submit() {
window.alert('关闭弹层');
this.isShow = false;
},
}
... ...
子组件my-mask:
<div class="mask" v-if="show"> <div class="mask-bg"></div> <alert v-bind="$attrs" v-on="$listeners"></alert> </div> ... ... components: { alert, // 孙组件 }, inheritAttrs: false, data() { return {} }, props: ['show'], ... ...
爷组件在传递数据给子组件的时候,如果子组件没有通过props接收祖组件传递的参数,那么这个数据会表现在子组件的根标签的属性上;通过设置 inheritAttrs 为 false,这些默认行为将会被去掉。
然后我们可以在子组件绑定v-bind="$attrs",将这些特性传递给孙组件,孙组件通过props接收数据,同理可以通过 $listeners 实现爷孙之间的事件监听器传递。
孙组件alert:
<div class="alert">
<h2>{{title}}</h2>
<div class="alert-con">{{con}}</div>
<button class="submit" @click="submit">确定</button>
</div>
... ...
data() {
return {}
},
props: ['title', 'con'], // title和con来自于爷组件
methods: {
submit() {
this.$emit('on-submit'); // 会触发爷组件的submit事件
}
}
... ...
方式二. 利用provide/inject 实现祖孙组件间的数据传递和事件监听
provide 和 inject 主要为高阶插件/组件库提供用例,允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。
例:
爷组件:
<div>
<my-con></my-con>
</div>
... ...
components: {
myCon, // 子组件
},
provide() {
return {
store: this.store
}
},
data() {
return {
store: {
state: {
type: 0
},
commit (type, value) {
this.state[type] = value
}
},
};
},
methods: {
changeCon() {
this.store.state.type ++;
if(this.store.state.type > 2) this.store.state.type = 0;
},
},
... ...
子组件my-con:
<div>
<my-table></my-table>
</div>
... ...
components: {
myTable, // 孙组件
},
props: [],
... ...
孙组件my-table:
<div>
<div class="tab-list">
<span class="tab-item" v-for="(item, index) in list" @click="switchType(item.type)" :class="{'active': item.type === store.state.type}">{{item.value}}</span>
</div>
</div>
... ...
data() {
return {
tableType: 0,
list: [{value: '新闻', type: 0}, {value: '汽车', type: 1},{value: '娱乐', type: 2}]
}
},
inject: ['store'],
methods: {
switchType(value) {
this.store.commit('type', value)
}
}
... ...
