依赖注入(provide-inject)
前言-关于Vue组件的通讯方式
父子组件:
父向子传递数据是通过 props,子向父是通过 events($emit);
通过父链 / 子链也可以通信($parent / $children);
ref 也可以访问组件实例;
$root 获取根组件
provide / inject;
$attrs/$listeners;
兄弟通信:
EventBus
vuex
通过共同的父亲进行传递信息
跨级通信:
EventBus
vuex
provide / inject
$attrs/$listeners;
父子层层传递
1、什么是依赖注入
在我们日常开发的过程中,我们需要从父组件向子组件传递数据,会使用 props;如果组件层级过多,使用 props 沿着组件链逐级传递下去,十分的麻烦, provide 和 inject 就可以解决这一问题。
允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,父组件可以为其所有的后代组件提供依赖,并在起上下游关系成立的时间里始终生效,不论组件层次有多深。
注意:它只做祖先通后代的 单向传递 的一个办法。
provide 就相当于 加强版父组件prop,可以跨越中间组件;
inject 就相当于 加强版子组件的 props。
2、使用方法
provide:提供变量,在父组件中使用,是对象,对象里面可以返回变量 / 函数;
inject:注入变量,在后代组件中使用,可以是数组 / 对象。
① 基本用法—非响应式
在祖先组件中使用provide传值,在子组件中用inject接收。
// 祖先组件
data() {
return {
name: "卷儿"
}
},
provide() {
return {
name: this.name
}
},
// 子组件
inject: ['name'],
<!-- 子组件中的使用方式 -->
{
{
name }}
注意:这种方法传递过来的数据是没有响应性的,当你改变祖先组件中的name时,子组件中接收的name并不会改变。
官方解释:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的 property 还是可响应的。
② 常规用法—非响应式
方法一:传递的参数用一个方法返回
// 祖先组件
data() {
return {
name: "卷儿"
}
},
provide() {
return {
newName: () => this.name
}
// 子组件
inject: ['newName'],
computed: {
hnewName() {
return this.newName()
}
}
//子组件使用:
<!-- 子组件中的使用方式 -->
<h2>{
{
hnewName }}</h2> <!-- 推荐使用这种方法 -->
<h2>{
{
newName() }}</h2>
方法二:把需要传递的参数定义成一个对象
官方解释:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的 property 还是可响应的。
// 祖先组件
data() {
return {
obj: {
name: "卷儿"
}
}
},
provide() {
return {
// 传递一个对象
obj: this.obj
}
},
// 子组件
inject: ['obj'],
computed: {
// 也可以不用计算属性重新定义
objName() {
return this.obj.name
}
}
<!-- 子组件中的使用方法 -->
<h2>obj的name: {
{
objName}}</h2>
<h2>obj的name: {
{
obj.name}}</h2>
③ 不太常规写法(响应式)
祖先组件使用provide传递整个this
// 祖先组件
data() {
return {
name: "卷儿"
}
},
provide() {
return {
app: this, // 传递整个this过去
};
}
inject: ["app"],// 拿到祖先组件的this
mounted() {
console.log(this.app.name) // this.app 下面都是响应式的,因为都是同一实例下的引用
},
3、总结
- provide/inject 是解决深层次的组件之间的通信问题,不受层级结构的限制。
- 不能随便去滥用,通信代表着耦合;
优点:
祖先组件不需要知道哪些后代组件使用它提供的数据;
后代组件不需要知道被注入的数据来自哪里;
不受层级结构的限制。
缺点:
组件间的耦合较为紧密,不易重构;