1、provide/inject有什么用?
常用的父子组件通信方式都是父组件绑定要传递给子组件的数据,子组件通过props
属性接收,一旦组件层级变多时,采用这种方式一级一级传递值非常麻烦,而且代码可读性不高,不便后期维护。
vue
提供了provide
和inject
帮助我们解决多层次嵌套嵌套通信问题。在provide
中指定要传递给子孙组件的数据,子孙组件通过inject
注入祖父组件传递过来的数据。
其实,provide
和 inject
主要为高阶插件/组件库提供用例。并不推荐直接用于应用程序代码中。比如elementUI
组件库中:
在el-form
组件中将组件实例暴露给子孙组件
在el-form-item
组件中注入el-form
组件实例,然后就可以使用el-form
组件实例的方法、变量等等。
为什么不使用父子组件props传值呢?
因为父子组件props
传值需要需要知道往哪一个子组件传值,而el-form
组件中会注入的子组件是不确定的。provide
只需要将传递的值抛出,不需要知道使用哪一个子组件,子组件通过inject
注入获取数据,也不需要知道父组件是谁,因此再封装组件库的时候很便利。
不推荐直接使用在应用程序代码中是因为数据追踪比较困难,不知道是哪一个层级声明了这个或者不知道哪一层级或若干个层级使用了。
2、provide/inject使用方式
provide
:是一个对象,或者是一个返回对象的函数。里面呢就包含要给子孙后代的东西,也就是属性和属性值。注意:子孙层的provide
会掩盖祖父层provide
中相同key
的属性值
inject
:一个字符串数组,或者是一个对象。属性值可以是一个对象,包含from
和default
默认值,from
是在可用的注入内容中搜索用的 key
(字符串或 Symbol
),意思就是祖父多层provide
提供了很多数据,from
属性指定取哪一个key
;default
指定默认值。
一种最常见的用法是刷新vue组件
3、例子
<template>
<div
id="app"
>
<router-view
v-if="isRouterAlive"
/>
</div>
</template>
<script>
export default {
name: 'App',
components: {
MergeTipDialog,
BreakNetTip
},
data () {
return {
isShow: false,
isRouterAlive: true
},
// 父组件中返回要传给下级的数据
provide () {
return {
reload: this.reload
}
},
methods: {
reload () {
this.isRouterAlive = false
this.$nextTick(() => {
this.isRouterAlive = true
})
}
}
}
</script>
<template>
<popup-assign
:id="id"
@success="successHandle"
>
<div class="confirm-d-tit"><span class="gray-small-btn">{{ name }}</span></div>
<strong>将被分配给</strong>
<a
slot="reference"
class="unite-btn"
>
指派
</a>
</popup-assign>
</template>
<script>
import PopupAssign from '../PopupAssign'
export default {
//引用vue reload方法
inject: ['reload'],
components: {
PopupAssign
},
methods: {
// ...mapActions(['freshList']),
async successHandle () {
this.reload()
}
}
}
</script>
这样就实现了子组件调取reload方法就实现了刷新vue组件的功能,个人认为它实现了组件跨越组件传递数据方法。
下面一个例子祖组件的数据,祖孙元素调取
Ancestor.vue
<template>
<div id="app">
</div>
</template>
<script>
export default {
data () {
return {
datas: [
{
id: 1,
label: '产品一'
},
{
id: 1,
label: '产品二'
},
{
id: 1,
label: '产品三'
}
]
}
},
provide {
return {
datas: this.datas
}
}
}
</script>
后代组件
<template>
<div>
<ul>
<li v-for="(item, index) in datas" :key="index">
{{ item.label }}
</li>
</ul>
</div>
</template>
<script>
export default {
inject: ['datas']
}
</script>
后代元素引入被注入数据datas,并在组件内循环输出
实际上,你可以把依赖注入看作一部分“大范围有效的 prop”,除了:
祖先组件不需要知道哪些后代组件使用它提供的属性
后代组件不需要知道被注入的属性来自哪里
提示:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的。