透传 props 的缺点
父子组件的 props 传递较为方便,但是层级增多后的透传管理比较困难:
此时应当使用 provide-inject 的依赖注入: 
provide
为组件后代提供数据:
ts
provide(/* 注入名 */ 'message', /* 值 */ 'hello!')特别地,可以从 main.ts 直接提供一个全局的 provide:
ts
const app = createApp({}) app.provide(/* 注入名 */ 'message', /* 值 */ 'hello!')inject
ts
const message = inject('message','defalut value')
const value = inject('key', () => new ExpensiveClass(), true,/*作为工厂函数*/)工厂函数 一个返回新创建对象的函数。这个函数抽象了对象创建的具体过程,使得代码更加灵活和可复用。
js
<template>
<div>
<p>Injected or Default Value: {{ value.data }}</p>
</div>
</template>
<script setup>
import { inject } from 'vue';
class ExpensiveClass {
constructor() {
console.log('ExpensiveClass is initialized');
this.data = 'Some expensive computation or resource initialization';
// 定义属性并赋值
}
}
// 使用 inject 获取 'key',若无值则使用工厂函数创建 ExpensiveClass 实例
const value = inject('key', () => new ExpensiveClass(), true);
// 检查 value 是否为 ExpensiveClass 实例并输出
if (value instanceof ExpensiveClass) {
console.log('ExpensiveClass instance:', value.data);
} else {
console.log('Injected value:', value);
}
</script>在注入方组件更改数据
要想在注入方更改供给方数据,需要在供给方定义一个更改数据的方法,并将其供给给注入方触发:
html
<!-- 在供给方组件内 -->
<script setup>
import { provide, ref } from 'vue'
const location = ref('North Pole')
function updateLocation() {
location.value = 'South Pole'
}
provide('location', {
location,
updateLocation
})
</script>
<!-- 在注入方组件 -->
<script setup>
import { inject } from 'vue'
const { location, updateLocation } = inject('location')
</script>
<template>
<button @click="updateLocation">{{ location }}</button>
</template>使用 readonly 包装器禁止注入方修改属性
ts
const count = ref(0)
provide('read-only-count', readonly(count))readonly 实质上是创建了一个 count 的代理对象,但其属性均为只读。 如果希望只有对象本身只读,而其中的属性值可以更改,可以使用 shallowReadonly。
使用 Symbol 作注入名
此前的注入名都是字符串形式的,但是在包含非常多依赖提供的大型应用中,最好使用 Symbol 作为注入名,用于创建唯一的标识符,这些标识符被用作注入的键。 首先,通过 Symbol() 创建并导出一个唯一的标识符:
ts
//keys.ts
export const myInjectedKey = Symbol()以该标识符为键创建 proide:
ts
import { myInjectedKey } from './keys';
provide(myInjectedKey,'hello i am parent')注入:
ts
import { myInjectedKey } from './keys';
const injection = inject(myInjectedKey, 'default value')这样便实现了在 keys.ts 中对键的集中管理,避免了键值冲突。