You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在TypeScript类中定义Vue响应式值遇问题,求解决方案

问题分析与解决方案

你的实现方式是可行的,但代码存在两个关键问题导致了报错:

1. Vue自动响应式转换导致Ref属性被解包

当你将Test实例赋值给test.value(test是一个ref)时,Vue会自动对这个实例进行响应式转换(ref的value为对象时,内部会调用reactive处理)。这个过程中,Vue会递归地将实例的属性转为响应式,对于已经是Ref类型的属性,Vue会自动解包成普通值,导致你类中的refValue从Ref<number>变成了number,所以调用init方法时访问this.refValue.value会报错(普通数值没有value属性)。

2. 模板标签语法错误

你的Test.vue模板结尾标签写错了,<template>应该闭合为</template>,错误的标签会导致模板解析异常,进一步影响响应式逻辑。


修正后的代码

Test.ts(无需修改)

import { ref, computed } from "vue";
import type { Ref, ComputedRef } from "vue";

export class Test {
    public refValue: Ref<number> = ref(0)
    public compValue: ComputedRef<string> = computed(() => {
        if (this.refValue.value === 0) return 'No Value given'
        else return `Value is ${this.refValue.value}`
    })

    constructor() {}

    public init() {
        this.refValue.value = 10
    }
}

Test.vue(修改两处)

<template>
  <div v-if="test">
    <span>{{ test.refValue }}</span>
    <span>{{ test.compValue }}</span>
  </div>
</template> <!-- 修正闭合标签 -->
<script setup lang="ts">
import { Test } from './Test.ts'
import { onMounted, ref, markRaw } from 'vue' // 引入markRaw

const test = ref<Test | null>(null)

onMounted(() => {
  // 用markRaw包裹实例,避免Vue自动响应式转换
  test.value = markRaw(new Test())
  test.value.init()
})
</script>

原理说明

  • markRaw可以标记一个对象,使其永远不会被Vue转为响应式对象,这样就能保留你类中refValue和compValue的原始Ref/ComputedRef类型,避免被自动解包。
  • 模板中访问test.refValue时,Vue会自动解包Ref对象的值,所以依然能正常显示响应式内容,不影响页面渲染。

内容的提问来源于stack exchange,提问作者LiiVion

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 11:47:20