基礎寫法(類型安全)
typescript
// parent.component.vue import { provide, ref } from 'vue' import type { InjectionKey } from 'vue'// 1. 定義類型化的 InjectionKey const COUNTER_KEY = Symbol() as InjectionKey<number> const USER_KEY = Symbol() as InjectionKey<{ name: string }>// 在 setup 中使用 setup() {const counter = ref(0)provide(COUNTER_KEY, counter) // 提供響應式數據const user = { name: 'John' }provide(USER_KEY, user) // 提供靜態對象return { counter } }
typescript
// child.component.vue import { inject } from 'vue' import type { InjectionKey } from 'vue'// 復用相同的 key const COUNTER_KEY = Symbol() as InjectionKey<number> const USER_KEY = Symbol() as InjectionKey<{ name: string }>setup() {// 2. 安全注入(帶默認值)const counter = inject(COUNTER_KEY, ref(0)) // 響應式數據const user = inject(USER_KEY, { name: 'Guest' }) // 靜態數據// 3. 強制注入(當確定父級已提供時)const forcedCounter = inject(COUNTER_KEY)!return { counter, user } }
<script setup>
?語法糖寫法
vue
<!-- Parent.vue --> <script setup lang="ts"> import { provide, ref } from 'vue'// 定義 key const messageKey = Symbol() as InjectionKey<string>const message = ref('Hello from parent') provide(messageKey, message) </script>
vue
<!-- Child.vue --> <script setup lang="ts"> import { inject } from 'vue'const messageKey = Symbol() as InjectionKey<string>// 注入 + 類型聲明 const message = inject(messageKey, 'default message')// 處理可能 undefined 的情況 const safeMessage = inject(messageKey) ?? 'fallback value' </script>
響應式對象注入
typescript
// types.ts export interface User {id: numbername: string }export const UserKey = Symbol() as InjectionKey<User>
vue
<!-- Parent.vue --> <script setup lang="ts"> import { provide, reactive } from 'vue' import { UserKey } from './types'const user = reactive({id: 1,name: 'Alice' })provide(UserKey, user) </script>
vue
<!-- Child.vue --> <script setup lang="ts"> import { inject } from 'vue' import { UserKey } from './types'const user = inject(UserKey)// 使用時需要處理可能 undefined 的情況 if (user) {console.log(user.name) // 類型安全 } </script>
最佳實踐提醒:
-
使用?
InjectionKey
:確保類型安全 -
默認值處理:
inject(key, defaultValue)
-
響應式數據:建議使用?
ref
/reactive
?保持響應性 -
代碼組織:推薦將 keys 集中管理在單獨文件中
-
安全判斷:當不確定是否已提供時,使用可選鏈操作符?
?.
typescript
// 推薦的文件結構 // src/provides/keys.ts import type { InjectionKey } from 'vue'export const API_KEY = Symbol() as InjectionKey<AxiosInstance> export const THEME_KEY = Symbol() as InjectionKey<'light' | 'dark'>
typescript
// 祖先組件
// 提供函數給后代,獲取受理樣品選集
provide("provideApplySampleSelection", handleApplySampleSelectionChange);
// 獲取受理樣品表格勾選的行數據
const handleApplySampleSelectionChange = (newSelection: ApplySample[]) => {//獲取勾選行數據applySampleTableSelection.value = newSelection;// 控制按鈕編輯狀態buttonDisabled();
};// 提供數據給后代
// 受理樣品列表
provide("applySampleList", applySampleTableData); // applySampleTableData是個Ref對象,不需要.value,傳遞ref對象本身(響應式數據)
// 受理類別
provide("acceptType",computed(() => applyBasicInfo.value.acceptType) // applyBasicInfo.value.acceptType 是派生數據(屬性數據),通過computed提供響應式數據
);
// 操作指令類型:新增刪除:info-add;修改:info-modify;查看:info-view
provide("operateCommandType", ref("info-add"));
// 滾動到離頂部表頭的距離
provide("scrollTop", applySampleTableScrollTop); // applySampleTableScrollTop是個Ref對象,不需要.value,傳遞ref對象本身(響應式數據)// 后代組件
// 注入祖先提供的函數
const sendApplySampleSelection = inject("provideApplySampleSelection", (data: ApplySample[]) => {});// 獲取受理樣品表格勾選的行數據
const handleApplySampleSelectionChange = (newSelection: ApplySample[]) => {// 向祖先組件發送表格選集sendApplySampleSelection(newSelection);
};// 接收祖先提供的數據
// 受理樣品列表
const applySampleList = inject<Ref<ApplySample[]>>("applySampleList", ref([]));
// 受理類別
const acceptType = inject<Ref<string>>("acceptType", ref(""));
// 操作指令類型:新增刪除:info-add;修改:info-modify;查看:info-view
const operateCommandType = inject<Ref<"info-add" | "info-modify" | "info-view">>("operateCommandType", ref("info-add"));
// 滾動到離頂部表頭的距離
const scrollTop = inject<Ref<number>>("scrollTop", ref(0));
?