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

Vue3+TypeScript+vue-class-component中Template Ref未作为Ref对象的问题排查及疑惑

问题解决:vue-class-component中模板Ref的正确用法

嘿,我一眼就看出问题出在哪了——你在vue-class-component的类组件里误用了Composition API的ref()函数来声明模板Ref!这就是导致TypeScript和浏览器行为矛盾的核心原因。

核心原因解释

在vue-class-component的类组件体系里,模板Ref的用法和普通Composition API写法完全不同:
你不需要手动调用ref()来创建Ref对象,只需要在类里声明一个和模板中ref属性同名的属性,Vue会自动把对应的DOM元素(或组件实例)直接赋值给这个属性。也就是说,这个类属性本身就是DOM元素,而不是包裹它的Ref对象。

你的代码里的矛盾点就源于此:

  • 你手动写了private testDiv = ref();,创建了一个空的Ref对象,但Vue在组件挂载时,会把模板里<div ref="testDiv">对应的真实DOM元素直接赋值给this.testDiv,直接覆盖了你手动创建的Ref对象。
  • 这就导致:浏览器里this.testDiv是真实DOM元素,所以this.testDiv.classList能正常工作;但TypeScript根据你写的ref()调用,推断testDiv是Ref类型,所以会提示“Property 'classList' does not exist on type 'Ref'”。
  • 当你尝试this.testDiv.value?.classList时,因为this.testDiv已经被替换成了DOM元素(不是Ref对象),它根本没有value属性,自然会抛出undefined错误。

修正后的代码

<template>
  <div id="test-div" ref="testDiv" />
</template>
<script lang="ts">
import { Options, Vue } from 'vue-class-component';
// 导入DOM类型以获得更好的TypeScript提示(可选,但推荐)
import type { HTMLDivElement } from '@vue/runtime-dom';

@Options({
  components: {},
})
export default class App extends Vue {
  // 直接声明属性,无需调用ref(),用非空断言告诉TS这个属性会被Vue赋值
  private testDiv!: HTMLDivElement;

  mounted(): void {
    console.log(this.testDiv); // TS和浏览器都认定这是HTMLDivElement
    console.log(this.testDiv.classList); // 两边都能正常工作
  }
}
</script>
<style lang="scss"></style>

额外说明

  • 代码里的!是非空断言,用来告诉TypeScript:这个属性会在组件挂载后被Vue赋值,不会是undefined。如果你不想用非空断言,也可以把属性声明为private testDiv?: HTMLDivElement;,然后使用时加可选链this.testDiv?.classList。
  • vue-class-component的文档其实明确提到了这个规则,只是可能你没留意:类组件中,模板里的ref属性值与类属性名对应时,Vue会自动完成DOM元素/组件实例的绑定,无需手动创建Ref对象。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 15:28:15