在 Vue 2 和 Vue 3 中,provide 和 inject 都是用于组件间跨层级通信的 API,允许祖先组件向其所有后代组件传递数据,而无需手动逐层传递 props。但两者在用法上存在一些差异:
Vue 2 中的 provide/inject
在 Vue 2 中,provide 和 inject 需要在组件选项中定义:
javascript
// 父组件 - 提供数据
export default {
provide() {
return {
// 可以提供静态值
appName: 'My App',
// 也可以提供响应式数据
user: this.user
}
},
data() {
return {
user: { name: 'John' }
}
}
}
// 后代组件 - 注入数据
export default {
inject: ['appName', 'user'],
mounted() {
console.log(this.appName) // 'My App'
console.log(this.user.name) // 'John'
}
}
Vue 2 中的特点:
-
provide选项是一个对象或返回对象的函数 -
inject选项是一个字符串数组或对象 -
注入的数据默认不是响应式的,如果需要响应式需提供响应式对象
-
可以通过对象形式注入并设置默认值:
javascriptinject: { appName: { from: 'appName', // 来源名,可省略(与key相同时) default: 'Default App' } }
Vue 3 中的 provide/inject
Vue 3 中保留了选项式 API 的用法,同时新增了组合式 API 的用法:
选项式 API(与 Vue 2 类似)
javascript
// 父组件
export default {
provide() {
return {
appName: 'My App',
user: this.user
}
},
data() {
return {
user: { name: 'John' }
}
}
}
// 后代组件
export default {
inject: ['appName', 'user'],
mounted() {
console.log(this.appName)
}
}
组合式 API(新增)
javascript
// 父组件
import { provide, ref, reactive } from 'vue'
export default {
setup() {
const appName = ref('My App')
const user = reactive({ name: 'John' })
// 提供数据
provide('appName', appName)
provide('user', user)
}
}
// 后代组件
import { inject } from 'vue'
export default {
setup() {
// 注入数据
const appName = inject('appName', 'Default App') // 第二个参数是默认值
const user = inject('user')
return {
appName,
user
}
}
}
Vue 3 中的主要变化:
- 新增了组合式 API 中的
provide和inject函数 - 可以直接提供响应式数据(ref/reactive),注入后保持响应性
- 注入时可以更方便地设置默认值
- 推荐使用 Symbol 作为注入键,避免命名冲突:
javascript
// keys.js
export const appNameKey = Symbol()
// 父组件
import { appNameKey } from './keys.js'
provide(appNameKey, 'My App')
// 后代组件
import { appNameKey } from './keys.js'
const appName = inject(appNameKey)
总结差异
- API 形式:Vue 3 同时支持选项式和组合式 API,Vue 2 仅支持选项式
- 响应式处理:Vue 3 中提供 ref/reactive 可以直接保持响应性,Vue 2 需手动处理
- 默认值设置:Vue 3 组合式 API 中通过第二个参数直接设置默认值,更简洁
- 类型支持:Vue 3 对 TypeScript 有更好的支持,可通过泛型指定注入类型
在实际开发中,provide 和 inject 适合传递应用级别的配置或深层嵌套组件间的通信,但不推荐过度使用,以免组件耦合度过高。