一、provide 和 inject 概述
在 Vue3 中,provide?和?inject?是一對用于實現跨層級組件通信的 API,它們解決了 props 需要逐層傳遞的繁瑣問題。
1.1 基本概念
provide (提供):在祖先組件中提供數據
inject (注入):在任意后代組件中注入這些數據
1.2 與 props 的對比
| 特性 | props | provide/inject |
|---|---|---|
| 傳遞方向 | 父 → 子 | 祖先 → 任意后代 |
| 層級限制 | 必須逐層傳遞 | 可跨任意層級 |
| 適用場景 | 直接父子組件通信 | 主題/配置/全局數據 |
| 響應性 | 默認支持 | 需要額外處理 |
二、基本使用方法
2.1 選項式 API 寫法
javascript
// 祖先組件
export default {provide: {theme: 'dark'}
}// 后代組件
export default {inject: ['theme'],created() {console.log(this.theme) // 輸出 'dark'}
}2.2 組合式 API 寫法(推薦)
html
<!-- 祖先組件 -->
<script setup>
import { provide } from 'vue'// 提供靜態數據
provide('theme', 'dark')// 提供響應式數據
const count = ref(0)
provide('count', count)
</script><!-- 后代組件 -->
<script setup>
import { inject } from 'vue'// 注入數據
const theme = inject('theme')
const count = inject('count')// 設置默認值
const size = inject('size', 'default') // 如果沒有提供 size,則使用 'default'
</script>三、響應式處理
3.1 保持響應性
html
<script setup>
import { provide, ref } from 'vue'const count = ref(0)
provide('count', count)// 在提供者中修改
function increment() {count.value++
}
</script><!-- 后代組件 -->
<script setup>
import { inject } from 'vue'const count = inject('count')// 注入的值會自動保持響應性
watch(count, (newVal) => {console.log('count changed:', newVal)
})
</script>3.2 提供修改方法(推薦模式)
html
<script setup>
import { provide, ref } from 'vue'const count = ref(0)// 同時提供值和修改方法
provide('count', {count,increment: () => count.value++
})
</script><!-- 后代組件 -->
<script setup>
const { count, increment } = inject('count')
</script>四、高級用法
4.1 使用 Symbol 作為 key
避免命名沖突:
javascript
// keys.js
export const THEME_KEY = Symbol('theme')// 提供者
import { THEME_KEY } from './keys'
provide(THEME_KEY, 'dark')// 注入者
const theme = inject(THEME_KEY)4.2 應用層 provide
在應用級別提供全局數據:
javascript
// main.js
import { createApp } from 'vue'
import App from './App.vue'const app = createApp(App)
app.provide('appVersion', '1.0.0')
app.mount('#app')4.3 結合 TypeScript 使用
typescript
interface User {id: numbername: string
}// 提供者
const user = ref<User>({ id: 1, name: 'John' })
provide<User>('user', user)// 注入者
const user = inject<User>('user')五、最佳實踐
避免濫用:只在確實需要跨多層組件通信時使用
命名規范:使用有意義的鍵名或 Symbol
文檔說明:為提供的屬性添加注釋說明
響應式處理:確保正確處理響應式數據
類型安全:在 TypeScript 項目中定義清晰接口
六、典型應用場景
主題切換功能
國際化實現
用戶身份信息共享
全局配置參數
復雜表單中的狀態共享
七、完整示例
7.1 主題切換實現
html
<!-- ThemeProvider.vue -->
<script setup>
import { provide, ref } from 'vue'const theme = ref('light')
const toggleTheme = () => {theme.value = theme.value === 'light' ? 'dark' : 'light'
}provide('theme', {theme,toggleTheme
})
</script><template><slot />
</template><!-- App.vue -->
<template><ThemeProvider><NavBar /><Content /></ThemeProvider>
</template><!-- NavBar.vue -->
<script setup>
const { theme, toggleTheme } = inject('theme')
</script><template><button @click="toggleTheme">當前主題: {{ theme }}</button>
</template>八、注意事項
不是響應式的:如果直接提供基本類型值,注入的值不會是響應式的
避免直接修改:除非明確設計如此,否則避免在注入組件中直接修改注入的值
組件封裝性:過度使用會破壞組件獨立性,使組件更難復用
九、總結
provide?和?inject?是 Vue3 中強大的跨組件通信工具,特別適合解決"prop 逐級透傳"問題。正確使用它們可以:
簡化深層嵌套組件間的通信
實現全局狀態管理(輕量級替代 Vuex/Pinia)
創建可復用的上下文組件