在 Vue 中,Provide/Inject
默认情况下传递的数据是非响应式的,但我们可以通过一些技巧让其支持动态数据更新。实现方式在 Vue 2 和 Vue 3 中略有不同,下面分别说明:
Vue 2 中实现动态数据
Vue 2 中 provide
提供的数据本身不会响应式更新,但可以通过以下两种方式实现动态效果:
1. 传递响应式对象(推荐)
将数据包装在 data
中的响应式对象里,provide
提供整个对象,后代组件注入后可直接访问响应式属性。
vue
<!-- 父组件 Parent.vue -->
<script>
export default {
data() {
return {
// 响应式对象
userInfo: {
name: "张三",
age: 20
}
}
},
provide() {
return {
// 提供整个响应式对象
userInfo: this.userInfo
}
},
methods: {
updateData() {
// 修改数据(响应式更新)
this.userInfo.name = "李四"
this.userInfo.age = 22
}
}
}
</script>
<!-- 后代组件 Child.vue -->
<script>
export default {
inject: ['userInfo'], // 注入响应式对象
mounted() {
console.log(this.userInfo.name) // 初始值:"张三"
}
}
</script>
<template>
<!-- 视图会自动更新 -->
<div>姓名:{{ userInfo.name }}, 年龄:{{ userInfo.age }}</div>
</template>
2. 传递访问数据的函数
如果只需传递单个属性而非整个对象,可提供一个返回该属性的函数,后代组件调用函数获取最新值。
vue
<!-- 父组件 Parent.vue -->
<script>
export default {
data() {
return { message: "初始消息" }
},
provide() {
return {
// 提供获取数据的函数
getMessage: () => this.message
}
},
methods: {
updateMessage() {
this.message = "更新后的消息" // 动态修改
}
}
}
</script>
<!-- 后代组件 Child.vue -->
<script>
export default {
inject: ['getMessage'],
data() {
return { currentMessage: "" }
},
mounted() {
this.currentMessage = this.getMessage() // 调用函数获取值
},
// 监听数据变化(需手动触发更新)
watch: {
getMessage() {
this.currentMessage = this.getMessage()
}
}
}
</script>
Vue 3 中实现动态数据
Vue 3 对 Provide/Inject
进行了增强,配合 ref
或 reactive
可以直接实现响应式:
1. 使用 ref 传递基本类型
vue
<!-- 父组件 Parent.vue -->
<script setup>
import { provide, ref } from 'vue'
// 创建响应式数据
const count = ref(0)
// 提供响应式数据
provide('count', count)
// 修改数据的方法
const increment = () => {
count.value++
}
</script>
<!-- 后代组件 Child.vue -->
<script setup>
import { inject } from 'vue'
// 注入响应式数据
const count = inject('count')
</script>
<template>
<div>当前计数:{{ count }}</div>
</template>
2. 使用 reactive 传递对象
vue
<!-- 父组件 Parent.vue -->
<script setup>
import { provide, reactive } from 'vue'
// 创建响应式对象
const user = reactive({
name: "张三",
age: 20
})
// 提供响应式对象
provide('user', user)
// 修改数据的方法
const updateUser = () => {
user.name = "李四"
user.age = 22
}
</script>
<!-- 后代组件 Child.vue -->
<script setup>
import { inject } from 'vue'
// 注入响应式对象
const user = inject('user')
</script>
<template>
<div>姓名:{{ user.name }}, 年龄:{{ user.age }}</div>
</template>
核心原理
- Vue 2:通过传递「响应式对象」或「返回数据的函数」,利用 Vue 本身的响应式系统(Object.defineProperty)实现动态更新。
- Vue 3 :
ref
和reactive
创建的响应式数据本身具有追踪能力,provide
传递后,后代组件注入的是响应式数据的引用,因此能自动更新。
注意事项
- Vue 2 中,若直接提供基本类型(如
provide() { return { count: this.count } }
),修改this.count
后,后代组件不会更新。 - Vue 3 中,尽量避免解构注入的响应式对象(如
const { name } = inject('user')
),这会丢失响应性,应直接使用user.name
。
通过上述方法,Provide/Inject
可以灵活支持动态数据传递,尤其适合深层嵌套组件的通信场景。