登录
首页 >  文章 >  前端

Vue3TypeScript深度响应式类实现

时间:2026-05-28 22:19:05 137浏览 收藏

在 Vue 3 + TypeScript 项目中,若希望自定义类(如 `MasterClass`)的嵌套属性(如 `items` 数组)真正实现深度响应式更新,并让所有业务逻辑自然内聚于类内部,关键在于摒弃 `ref()` 包裹普通类实例的惯用做法,转而使用 `reactive()` 直接将类实例转化为深度响应式代理——这样不仅能让 `has_items` 的 setter 自动触发 `items` 清空、数组操作(push/length=0)实时反映到模板渲染,还能保持类型安全与代码可维护性,堪称面向对象思维与 Vue 响应式系统高效协同的最佳实践。

Vue 3 中使用 TypeScript 实现深度响应式的类封装

在 Vue 3 + TypeScript 项目中,若需让自定义类实例(如 masterClass)的嵌套属性(如 items 数组)具备深度响应性,并将业务逻辑完全封装在类内部,应使用 reactive() 而非 ref() 包裹类实例。

在 Vue 3 + TypeScript 项目中,若需让自定义类实例(如 `masterClass`)的嵌套属性(如 `items` 数组)具备深度响应性,并将业务逻辑完全封装在类内部,应使用 `reactive()` 而非 `ref()` 包裹类实例。

Vue 3 的响应式系统对不同 API 有明确分工:ref() 默认仅对 .value 层级做浅层响应(即仅追踪 ref 本身是否被重新赋值),而其内部对象的深层变更(如 record.items.push(...) 或 record.has_items = false 触发的 _items 清空)不会自动触发模板更新——除非该对象本身也是由 reactive() 创建的响应式代理。

你当前的代码使用 ref 存储类实例,虽类型安全,但 masterClass 实例本身仍是普通 JavaScript 对象,不具备响应式能力。因此,即使你在 set has_items 中调用 this._items.splice(0) 清空数组,Vue 也无法侦测到 record.items 的变化,导致 不会重新渲染。

✅ 正确做法:使用 reactive() 将 masterClass 实例转为深度响应式对象,并显式标注类型:

// masterClass.ts —— 建议升级为 class 命名规范(PascalCase)并添加类型注解
export class MasterClass {
  private _id: number = 0;
  private _has_items: boolean = false;
  private _items: DetailsClass[] = [];

  get id(): number {
    return this._id;
  }
  set id(value: number) {
    this._id = value;
  }

  get has_items(): boolean {
    return this._has_items;
  }
  set has_items(value: boolean) {
    this._has_items = value;
    // ✅ 类内逻辑:自动同步 items 状态
    if (!value) {
      this._items.length = 0; // 更语义化且高效于 splice(0)
    }
  }

  get items(): DetailsClass[] {
    return this._items;
  }
  set items(value: DetailsClass[]) {
    this._items = value;
  }
}

export class DetailsClass {
  private _id: number = 0;
  private _price: number = 0;

  get id(): number { return this._id; }
  set id(value: number) { this._id = value; }

  get price(): number { return this._price; }
  set price(value: number) { this._price = value; }
}
<!-- masterView.vue -->
<template>
  <div v-if="record">
    <label>Has Items</label>
    &lt;select v-model=&quot;record.has_items&quot;&gt;
      <option :value="true">Yes</option>
      <option :value="false">No</option>
    &lt;/select&gt;

    <br /><br />

    <table>
      <tbody>
        <tr v-for="element in record.items" :key="element.id">
          <td>{{ element.id }}</td>
          <td>{{ element.price }}</td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script setup lang="ts">
import { reactive } from 'vue';
import { MasterClass } from './masterClass'; // 路径按实际调整

// ✅ 使用 reactive 包裹 new MasterClass(),获得深度响应性
// 类型推导自动生效,无需额外泛型(但可显式标注增强可读性)
const record = reactive<MasterClass>(new MasterClass());
</script>

⚠️ 注意事项:

  • reactive() 仅接受对象(包括 class 实例),不支持 null、原始类型或 undefined;因此 v-if="record" 可直接使用(record 始终为有效响应式对象)。
  • v-model 绑定 record.has_items 时,<select> 的 value 必须为布尔类型(true/false),而非字符串 "true"/"false",否则类型不匹配会导致绑定失效。示例中已使用 :value="true" 保证类型正确。
  • 类中所有响应式依赖的属性(如 _items)必须通过 reactive 或 ref 管理;此处因 _items 是 record 的深层属性,且 record 本身是 reactive() 创建的代理,故 _items 数组操作(如 push、length = 0)均可被 Vue 自动追踪。
  • 若需在 setup 中访问原始类实例(如调用非响应式方法),可保留 const raw = new MasterClass(),但响应式交互务必通过 reactive() 实例进行。

总结:将业务逻辑封装在类中是良好实践,但需与 Vue 响应式机制协同——reactive() 是使 class 实例具备深度响应能力的关键桥梁。避免混合使用 ref 包裹非响应式对象,优先选择 reactive() 处理复杂状态树。

终于介绍完啦!小伙伴们,这篇关于《Vue3TypeScript深度响应式类实现》的介绍应该让你收获多多了吧!欢迎大家收藏或分享给更多需要学习的朋友吧~golang学习网公众号也会发布文章相关知识,快来关注吧!

资料下载
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>