登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  前端

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; }
}



⚠️ 注意事项:

  • reactive() 仅接受对象(包括 class 实例),不支持 null、原始类型或 undefined;因此 v-if="record" 可直接使用(record 始终为有效响应式对象)。
  • v-model 绑定 record.has_items 时,