在vue项目中,如果遇到跨组件多层次传值的话,一般会用到vuex,或者其他第三方共享状态管理模式,如pinia等,但是对于父组件与多层次孙子组件时,建议使用provide 与 inject,与之其他方式相比,简单方便。
基础使用
Vue2 option api
# App.vue
<template>
<parent/>
</template>
<script>
import Parent from "@/components/parent.vue";
export default {
name: 'App',
components: {Parent},
provide: {
word: 'Hello Word'
}
}
</script>
# parent.vue
<template>
<child />
</template>
<script>
import Child from "@/components/child.vue";
export default {
name: "parent",
components: {Child}
}
#child.vue
<template>
<span>{{ word }}</span>
</template>
<script>
export default {
name: "child",
inject: ['word']
}
在界面就显示出相应内容。
inject 与 props 是相似,可以是一个数组也可以是一个对象,如果是对象的话,可以为每一个属性另设别名,默认值。如下
inject: {
childWord: {
from: 'word',
default: '默认值'
}
}
childWord 是孙子组件另起的别名;from 数据来源字段;default 默认值,default 与 props 中的 default 一样,如果默认值是一个对象的话,default 值必须是一个工厂函数返回值。
Vue3 composition api
# App.vue
<template>
<parent />
</template>
<script setup>
import Parent from "@/components/parent.vue";
import {provide} from "vue";
provide('word', 'Hello Vue3.0')
</script>
# chile.vue
<template>
{{ word }}
</template>
<script setup>
import { inject } from "vue";
const word = inject('word');
</script>
inject 默认值
const word = inject('word', '默认值');
或者
const word = inject('word', () => {});
在 Vue3.0 中响应式数据传递,因为没有 this 所限制,可以直接传递 ref ,或 reactive 值,如下
let val = ref(0);
provide('word', val.value);
或者
provide('word', val)
对于 ref 数据有没有 .value 都可以,因为在 provide 中 会通过 isRef 函数去判断当前值是否为 ref 数据,如果是,Vue 会自动 通过 toValue 函数去取值。
注意
provide 与 inject 可以传递响应式数据,但是 provide 必须是一个函数返回值,与组件中的 data 一样,原因是,如果是一个普通的对象的话,this 指向的是 undefined ,不是该组件实例,这里是运用到的了闭包函数,使得this 指向当前组件实例。
# App.vue
provide: {
context: this
}
# child.vue
inject: ['context'],
mounted() {
console.log(this.context);
}
这时控制台打印出来的 this 值是 undefined。
如果 provide 是一个函数的话,打印出来的就是当前实例对象。
provide 也不能是一个箭头函数,因为箭头函数还会改变 this 的指向。
provide: () => {
return {
context: this
}
}
这时 this 指向的也是 undefined。