关于 vue3 computed 属性无法自动解包的问题

一般情况下,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 拦截,外部使用的时候访问的是代理的对象属性。