依赖注入
Props 逐级传递存在的问题:

使用 Pinia 能够解决该问题,但是如果不用 Pinia 呢?
可以用依赖注入。
快速上手
整个依赖注入分为两个角色:
- 提供方:负责提供数据
- 注入方:负责接收数据
1. 提供方
要提供数据,可以使用 provide 方法。例如:
vue
<script setup>
import { provide } from 'vue'
provide(/* 数据名称 */ 'message', /* 实际数据 */ 'hello!')
provide('message', 'hello!')
</script>
该方法接收的参数也很简单:
- 数据对应的名称
- 实际的数据
2. 注入方
注入方通过 inject 方法来取得数据。例如:
vue
<script setup>
import { inject } from 'vue'
const message = inject('message')
</script>
相关细节
1. 非 setup 语法糖
如果没有使用 setup 语法糖,那么需要保证 provide 和 inject 方法是在 setup 方法中同步调用的:
js
import { provide } from 'vue'
export default {
setup() {
provide(/* 注入名 */ 'message', /* 值 */ 'hello!')
}
}
js
import { inject } from 'vue'
export default {
setup() {
const message = inject('message')
return { message }
}
}
因为 Vue 的依赖注入机制需要在组件初始化期间同步建立依赖关系,这样可以确保所有组件在渲染之前就已经获取到必要的依赖数据。如果 provide 和 inject 在 setup 之外或异步调用,Vue 无法保证组件初始化完成之前所有的依赖关系已经正确建立。
2. 全局依赖提供
js
// main.js
import { createApp } from 'vue'
const app = createApp({})
app.provide(/* 注入名 */ 'message', /* 值 */ 'hello!')
在应用级别提供的数据在该应用内的所有组件中都可以注入。
3. 注入默认值
注入方可以提供一个默认值,这一点类似于 props 的默认值。
js
// 如果没有祖先组件提供 "message"
// value 会是 "这是默认值"
const value = inject('message', '这是默认值')
4. 提供响应式数据
提供方所提供的值可以是任意类型的值,包括响应式的值。
注意点:
如果提供的值是一个 ref,注入进来的会是该 ref 对象,而不会自动解包为其内部的值。
尽可能将任何对响应式状态的变更都保持在提供方组件中
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>
使用 readonly 来提供只读值
vue<script setup> import { ref, provide, readonly } from 'vue' const count = ref(0) provide('read-only-count', readonly(count)) </script>
5. 使用Symbol作为数据名
大型的应用建议最好使用 Symbol 来作为注入名以避免潜在的冲突。推荐在一个单独的文件中导出这些注入名 Symbol:
js
// keys.js
export const myInjectionKey = Symbol()
js
// 在供给方组件中
import { provide } from 'vue'
import { myInjectionKey } from './keys.js'
provide(myInjectionKey, { /* 要提供的数据 */ });
js
// 注入方组件
import { inject } from 'vue'
import { myInjectionKey } from './keys.js'
const injected = inject(myInjectionKey)
实战案例:整个应用程序在多个组件中共享一些全局配置(主题颜色、用户信息...)
-EOF-