依赖注入
prop逐级透传
某个深层的子组件需要一个较远的祖先组件中的部分数据。在这种情况下,如果仅使用 props 则必须将其沿着组件链逐级传递下去,这会非常麻烦:

Provide
基本语法
要为组件后代提供数据,需要使用到 provide函数:
ts
provide(name:string|Symbol,value:any)- name:注入名
- value:注入值
vue
<script setup>
import { provide } from 'vue'
provide(/* 注入名 */ 'message', /* 值 */ 'hello!')
</script>ts
import { provide } from 'vue'
export default {
setup() {
provide(/* 注入名 */ 'message', /* 值 */ 'hello!')
}
}一个组件可以多次调用 provide(),使用不同的注入名,注入不同的依赖值。
应用层Provide
除了在一个组件中提供依赖,我们还可以在整个应用层面提供依赖:
ts
import { createApp } from 'vue'
const app = createApp({})
app.provide(/* 注入名 */ 'message', /* 值 */ 'hello!')在应用级别提供的数据在该应用内的所有组件中都可以注入。这在你编写插件时会特别有用,因为插件一般都不会使用组件形式来提供值。
Inject
基本语法
要注入上层组件提供的数据,需使用 inject() 函数:
vue
<script setup>
import { inject } from 'vue'
const message = inject('message')
</script>ts
import { inject } from 'vue'
export default {
setup() {
const message = inject('message')
return { message }
}
}提示
如果有多个父组件提供了相同键的数据,注入将解析为组件链上最近的父组件所注入的值。
注入默认值
如果在注入一个值时不要求必须有提供者,那么我们应该声明一个默认值:
ts
// 如果没有祖先组件提供 "message"
// `value` 会是 "这是默认值"
const value = inject('message', '这是默认值')数据的修改性
inject 得到的数据能不能修改,取决于你修改的是 值本身 还是 引用里的内容。
- inject注入引用类型:
ts
// parent
provide('user', { name: 'Tom', age: 20 })ts
const user = inject('user')!
user.name = 'Jack' // ✅ 能修改对象本身- inject注入原始类型:
ts
// 父组件
provide('age', 18)ts
// 子组件
let age = inject('age')
age = 20 // 父组件的age没有改变,只是修改了子组件自己的局部变量和响应式数据配合使用
inject注入普通的引用类型虽然可以被修改,但是不会触发页面的重新渲染,我们可以inject响应式数据进行响应式追踪:
vue
// Parent.vue
<script setup lang="ts">
import { reactive, provide } from 'vue'
const user = reactive({
name: 'Tom',
age: 20
})
provide('user', user)
</script>当提供 / 注入响应式的数据时,建议尽可能将任何对响应式状态的变更都保持在供给方组件中。这样可以确保所提供状态的声明和变更操作都内聚在同一个组件内,使其更容易维护。
有的时候,我们可能需要在注入方组件中更改数据。在这种情况下,我们推荐在供给方组件内声明并提供一个更改数据的方法函数:
vue
<!-- 在供给方组件内 -->
<script setup>
import { provide, ref } from 'vue'
const location = ref('North Pole')
function updateLocation() {
location.value = 'South Pole'
}
provide('location', {
location,
updateLocation
})
</script>vue
<!-- 在注入方组件 -->
<script setup>
import { inject } from 'vue'
const { location, updateLocation } = inject('location')
</script>
<template>
<button @click="updateLocation">{{ location }}</button>
</template>