Provide/Inject
Provide/Inject是跨组件通信的一种解决方案。这对组合不同于props,父组件provide提供的数据,不管是多么深层级的子组件都可以Inject注入使用。
用法
假设有这么三个组件:Father.vue、Son.vue、GrandSon.vue。
这三个组件分别代表:父组件、子组件、孙子组件。
我现在要将父组件(Father.vue)的数据,传给孙子组件(GrandSon.vue)使用。 反过来就是孙子组件内(Father)要使用父组件(Father.vue)的数据。
如果使用props的话,我们需要一级一级往下传,非常的麻烦。
使用Provide/Inject的话就不需要这样,父组件提供数据,后代组件直接注入使用即可。
- provide:
Object | () => Object - inject:
Array<string> | { [key: string]: string | Symbol | Object }
根据官方的提示,project可以是一个对象也可以是一个返回值为对象的函数,推荐使用返回值为对象的函数的形式,inject可以是一个字符串数组,也可以是一个对象。
示例:
Father.vue:
<template>
<div class="dt-father">
<Son />
</div>
</template>
<script>
export default {
name: 'Father',
data() {
return {
message: 'dt-father'
}
},
// 提供给子组件的数据
provide () {
return {
fatherMessage: this.message
}
}
}
</script>
Son.vue:
<template>
<div class="dt-Son">
<GrandSon />
</div>
</template>
<script>
export default {
name: 'Son'
}
</script>
GrandSon.vue:
<template>
<div class="dt-grandson">
{{ fatherMessage() }} <!-- 结果:dt-father -->
</div>
</template>
<script>
export default {
name: 'GrandSon',
inject: ['fatherMessage']
}
</script>
从上面的示例可以看出,不用经过子组件,孙子组件就可以直接使用到父组件中的数据,这给深层子组件数据通信提供了大大的便利。
提供响应式的数据
vue官方说明:使用provide提供inject注入的数据不是响应式的。
也就是说数据更新了,但是视图不会跟着渲染更新。
那有什么办法让父组件提供的数据是响应式的呢?
官方也有提供说明,意思大概就是这样的:
如果父组件想要通过provide提供响应式的数据给子组件去使用,要么将该数据用一个方法返回,要么该数据封装在一个对象里,对象里的属性是响应式的。
将数据用一个方法返回
示例:
Father.vue:
<template>
<div class="dt-father">
<Son />
</div>
</template>
<script>
export default {
name: 'Father',
data() {
return {
message: 'dt-father'
}
},
// 提供给子组件的数据
provide () {
return {
fatherMessage: () => this.message
}
}
}
</script>
GrandSon.vue:
<template>
<div class="dt-grandson">
{{ fatherMessage() }} <!-- 结果:dt-father -->
</div>
</template>
<script>
export default {
name: 'GrandSon',
inject: ['fatherMessage']
}
</script>
### 将数据封装在一个对象里
示例:
`Father.vue`:
```html
<template>
<div class="dt-father">
<Son />
</div>
</template>
<script>
export default {
name: 'Father',
data() {
return {
message: 'dt-father'
}
},
// 提供给子组件的数据
provide () {
return {
fatherProvideData: {
fatherMessage: this.message
}
}
}
}
</script>
GrandSon.vue:
<template>
<div class="dt-grandson">
{{ fatherMessage() }} <!-- 结果:dt-father -->
</div>
</template>
<script>
export default {
name: 'GrandSon',
inject: ['fatherMessage']
}
</script>
修改inject注入的数据
子组件修改inject注入的数据,实际上是直接修改了provide提供数据的父组件中的数据。
引用类型例如数组、对象等可以直接provide子组件即可修改。基本类型需要使用将数据用一个方法返回的方式。
我们可以将需要修改的值作为参数传给函数,上面也看到了,子组件使用inject注入进来的数据需要函数式调用的,所以我们可以将需要修改的值当做参数传进去,然后再在父组件中provide中的函数内做逻辑处理。
示例:
Father.vue:
<template>
<div class="dt-father">
<Son />
</div>
</template>
<script>
export default {
name: 'Father',
data() {
return {
message: 'dt-father'
}
},
// 提供给子组件的数据
provide () {
return {
fatherProvideData: {
fatherMessage: (grandSonData) => {
this.message = grandSonData || this.message
return this.message
}
}
}
}
}
</script>
GrandSon.vue:
<template>
<div class="dt-grandson">
{{ fatherMessage() }} <!-- 结果:dt-father -->
<button @click="changeFatherMessage"></button>
</div>
</template>
<script>
export default {
name: 'GrandSon',
inject: ['fatherMessage'],
methods: {
// 修改父组件provide的数据
changeFatherMessage () {
this.fatherMessage('dt-grandson')
}
}
}
</script>