一般情况下,computed 属性在模板中使用会自动解包,不需要手动写 .value,但是,也存在需要手动写 .value 的情况。比如 setup 里非顶级变量。之所以碰到这种情况是因为……先贴代码吧,然后对着代码解释。
<script setup> import { ref, reactive, computed } from 'vue' class A { attrs = {} constructor() { this.attrs = reactive(this.attrs) } info = computed({ get:() => { return this.attrs.info ?? '' }, set: (val) => { this.attrs.info = val } }) } class B extends A { info = computed({ get: () => { return this.attrs.info?.endsWith('B') ? this.attrs.info : (this.attrs.info ?? '') + 'B' }, set: (val) => { this.attrs.info = val + 'B' } }) } const aInstance = reactive(new A()) const bInstance = new B() console.log(aInstance.info, aInstance.info.value) const msg = computed({ get() { return aInstance.info + bInstance.info.value }, set(val) { aInstance.info = val } }) aInstance.attrs.info = '1' </script> <template> <h1>{{ aInstance.info }}</h1> <input v-model="msg" /> <input v-model="bInstance.info.value" /> </template>

代码里有两个类 A 和 B,类中的 info 是 computed 属性。这样写是因为我想让类中的属性自动计算,这里也是为了验证实例化和继承是否仍然保留计算属性功能。结论是可以保留,但有一点要注意,计算属性的 get 和 set 要用箭头函数,因为计算属性的方法不是通过实例调用的,普通函数没有绑定到实例上。
然后是两个 input 的 v-model 绑定。msg 直接用,但 bInstance 的 info 需要 .value,因为 msg 是 setup 里的顶级变量,而 info 在 bInstance 里面。从结果来看,模板只会自动解构顶级变量。但这里有个奇怪的地方,那就是 aInstance 即使不用 reactive 包裹,h1 标签里的取值也不需要 .value。所以前面的结论可能是错误的。
之后是 msg 的定义。msg 的 get 方法里 aInstance 是没有 .value 的,因为 aInstance 通过 reactive 包裹了,reactive 通过 proxy 拦截,外部使用的时候访问的是代理的对象属性。