导航
通常,当我们需要从父组件向子组件传递数据时,我们使用 props。想象一下这样的结构:有一些深度嵌套的组件,而深层的子组件只需要父组件的部分内容。在这种情况下,如果仍然将 prop 沿着组件链逐级传递下去,可能会很麻烦。
官网的解释很让人疑惑,那我翻译下这几句话:
provide 可以在祖先组件中指定我们想要提供给后代组件的数据或方法,而在任何后代组件中,我们都可以使用 inject 来接收 provide 提供的数据或方法。
provide(name, value)inject(name, default value) 第二个参数可选
当父组件有很多数据需要分发给其子代组件的时候, 就可以使用 provide 和 inject 。
App.vue
<template>
<inject-child></inject-child>
</template>
<script>
import injectChild from '@/components/injectChild';
import { provide } from 'vue';
export default {
name: 'App',
components: {
injectChild
},
// provide: { // Vue2写法
// name: 'Lance',
// age: 28
// },
setup() {
// Vue3写法
provide('name', 'Lance');
provide('age', 28);
}
}
</script>
injectChild.vue
<template>
<div>
<div>{{ name }}</div>
<div>{{ age }}</div>
</div>
</template>
<script>
import { inject } from 'vue';
export default {
name: 'InjectChild',
// inject: ['name', 'age'] // Vue2写法
setup() {
// Vue3写法
const name = inject('name');
const age = inject('age', 'loading...');
return {
name,
age
}
}
}
</script>

App.vue
<template>
<div>
<inject-child></inject-child>
<button @click="changeName">改变名字</button>
</div>
</template>
<script>
import injectChild from '@/components/injectChild';
import { provide, ref } from 'vue';
export default {
name: 'App',
components: {
injectChild
},
setup() {
const name = ref('Lance');
provide('name', name);
provide('age', 28);
const changeName = () => {
name.value = 'GC'; // 子组件能监听到父组件对name的更改
}
return {
changeName
}
}
}
</script>
injectChild.vue
<template>
<div>
<div>{{ name }}</div>
<div>{{ age }}</div>
</div>
</template>
<script>
import { inject } from 'vue';
export default {
name: 'InjectChild',
setup() {
const name = inject('name');
const age = inject('age', 'loading...');
return {
name,
age
}
}
}
</script>
App.vue
<template>
<div>
<inject-child></inject-child>
</div>
</template>
<script>
import injectChild from '@/components/injectChild.vue';
import { provide, ref } from 'vue';
export default {
name: 'App',
components: {
injectChild
},
setup() {
const name = ref('Lance');
const changeName = () => {
name.value = 'GC';
}
provide('name', name);
// 父组件把更改函数通过 provide 传递给 子组件
provide('changeName', changeName);
}
}
</script>
injectChild.vue
<template>
<div>
<div>{{ name }}</div>
<button @click="changeName">改变名字</button>
</div>
</template>
<script>
import { inject } from 'vue';
export default {
name: 'InjectChild',
setup() {
const name = inject('name');
const changeName = inject('changeName');
return {
name,
changeName
}
}
}
</script>
App.vue
<template>
<div>
<inject-child></inject-child>
</div>
</template>
<script>
import injectChild from '@/components/injectChild_子组件改变provide.vue';
import { provide, ref, readonly } from 'vue';
export default {
name: 'App',
components: {
injectChild
},
setup() {
const name = ref('Lance');
const changeName = () => {
name.value = 'GC';
}
// 这样子组件就无法更改name了(如果不用readonly包裹,子组件可以直接更新 name.value)
provide('name', readonly(name));
// 父组件把更改函数通过 provide 传递给 子组件
provide('changeName', changeName);
}
}
</script>
injectChild.vue
<template>
<div>
<div>{{ name }}</div>
<button @click="changeName">改变名字</button>
<button @click="injectChildChangeName">子组件改变name</button>
</div>
</template>
<script>
import { inject } from 'vue';
export default {
name: 'InjectChild',
setup() {
const name = inject('name');
const changeName = inject('changeName');
const injectChildChangeName = () => {
name.value = 'Sherry'; // 无法更改父组件name
}
return {
name,
changeName,
injectChildChangeName
}
}
}
</script>


父组件
<template>
<div>祖先组件{{obj.lv1.lv2.num}}</div>
<button @click="obj.lv1.lv2.num++">按钮++</button>
<Child />
</template>
<script setup>
import Child from './Child.vue'
import { ref,provide,readonly } from 'vue';
// 为保证依赖注入是响应式,使用ref
let obj = ref({
name:'paul',
age:18,
lv1:{
lv2:{
num:666
}
}
})
// 看源码可知setup语法糖只支持一次provide一个变量
// 子孙组件可以直接逆向修改祖先组件的传递过来的值,这是不允许的。所以可以增加一个readonly,防止子组件修改祖先组件造成混乱。
provide('obj',readonly(obj))
</script>
子组件
<template>
<div>子组件{{obj?.lv1.lv2.num}}</div>
<GrandChild />
</template>
<script setup lang='ts'>
import GrandChild from './GrandChild.vue'
import { inject } from 'vue';
let obj = inject('obj')
</script>