一、官方文档
二、可以自动解包哪部分的数据
| 能被自动解包的类型 | 说明 | 是否需要 .value | 举例 |
|---|---|---|---|
ref 对象 | 自动访问 .value 属性 | ❌ | ref(1) 在 template 中直接 {{ count }} |
reactive 对象 | 保持响应式代理,不需要特殊处理 | ❌ | reactive({ name: 'abc' }),直接 user.name |
| 普通值(基本类型) | 字符串、数值、布尔直接返回使用 | ❌ | const name = 'Vue',{{ name }} |
| 计算属性(computed) | 自动访问 .value 属性 | ❌ | computed(() => count.value * 2) |
| 函数(方法) | 可以直接调用,不做处理 | ❌ | const inc = () => count.value++,直接 @click="inc" |
| props | 自动解包传进来的 props | ❌ | <MyComp title="hello" />,{{ title }} |
| emits / attrs / slots | 通过 context 提供,自动挂到 ctx | 有条件 | 插槽 slot 可直接用,attrs 通过 $attrs |
三、代码示例
- ref自动解包
<script setup>
import { ref } from 'vue'
const count = ref(0)
console.log(count.value) // setup中需要写count.value
</script>
<template>
<p>{{ count }}</p> <!-- 无需 count.value -->
</template>
- reactive 保持代理
<script setup>
import { reactive } from 'vue'
const user = reactive({ name: 'Alice' })
</script>
<template>
<p>{{ user.name }}</p> <!-- user对象是响应式代理 -->
</template>
- computed 自动解包
<script setup>
import { computed } from 'vue'
const double = computed(() => 2 * 3)
console.log(double.value) // setup中需要写double.value
</script>
<template>
<p>{{ double }}</p> <!-- double.value 自动解包 -->
</template>
- 方法直接调用
<script setup>
function greet() {
console.log('Hello!')
}
</script>
<template>
<button @click="greet">Greet</button>
</template>
- props 自动解包
<script setup>
defineProps(['title'])
</script>
<template>
<h1>{{ title }}</h1> // 无需props.title
</template>
三、自动解包工作原理
-
通过编译阶段(compiler)识别变量
-
在运行时,Vue 用
proxyRefs()(Vue内部方法)包装 setup 的返回对象 -
proxyRefs()逻辑就是:- 如果是
ref,访问时自动.value - 如果是其他普通对象,直接返回
- 如果是
function proxyRefs(object) {
return new Proxy(object, {
get(target, key) {
const val = target[key]
return isRef(val) ? val.value : val
},
set(target, key, value) {
const oldVal = target[key]
if (isRef(oldVal) && !isRef(value)) {
oldVal.value = value
return true
} else {
target[key] = value
return true
}
}
})
}
三、注意⚠️
| 类型 | 说明 | 要自己手动处理 |
|---|---|---|
| 深层次 ref | 比如 ref({ a: 1 }),访问 count.a 要小心 | |
| 复杂嵌套对象 | ref({ user: { name: 'abc' } }) 的 user 不是 proxy | |
| 自定义对象/类实例 | 不一定自动解包,除非你手动处理响应式 | |
| 外部返回的对象 | 某些第三方库(比如 axios)返回的对象,不会响应式 |