在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
相关产品推荐
相关产品推荐

