写点什么

鸿蒙 5.0 应用开发——V2 装饰器 @ObservedV2 和 @Trace 的使用

作者:高心星
  • 2025-09-17
    江苏
  • 本文字数:2784 字

    阅读完需:约 9 分钟

鸿蒙5.0应用开发——V2装饰器@ObservedV2和@Trace的使用

【高心星出品】

V2 装饰器 @ObservedV2 和 @Trace 的使用

概念

@ObservedV2 装饰器与 @Trace 装饰器是 HarmonyOS 状态管理 V2 中用于深度观测类属性变化的核心工具。它们主要解决嵌套类对象属性变化的观测难题,以下是关键特性和使用要点:


  • @ObservedV2 装饰器与 @Trace 装饰器需要配合使用,单独使用 @ObservedV2 装饰器或 @Trace 装饰器没有任何作用。

  • 被 @Trace 装饰器装饰的属性 property 变化时,仅会通知 property 关联的组件进行刷新。

  • 在嵌套类中,嵌套类中的属性 property 被 @Trace 装饰且嵌套类被 @ObservedV2 装饰时,才具有触发 UI 刷新的能力。

  • 在继承类中,父类或子类中的属性 property 被 @Trace 装饰且该 property 所在类被 @ObservedV2 装饰时,才具有触发 UI 刷新的能力。

  • 未被 @Trace 装饰的属性用在 UI 中无法感知到变化,也无法触发 UI 刷新。

  • @ObservedV2 的类实例目前不支持使用 JSON.stringify 进行序列化。

  • 使用 @ObservedV2 与 @Trace 装饰器的类,需通过 new 操作符实例化后,才具备被观测变化的能力。

一、核心机制
  1. 协同工作原则

  2. 必须同时使用 @ObservedV2(类级装饰器)和 @Trace(属性级装饰器)

  3. 单独使用任一装饰器均无效

  4. 示例结构:


   @ObservedV2   class User {     @Trace name: string;     @Trace address: Address;   }
复制代码


  1. 深度观测能力

  2. 支持嵌套类结构(如类 A 包含类 B 实例,B 又包含类 C 实例)

  3. 支持继承关系(父类/子类属性变化均能被观测)

  4. 仅被 @Trace 装饰的属性变化触发 UI 刷新

二、与 V1 版本的对比


三、关键限制条件
  1. 序列化限制:被 @ObservedV2 装饰的类实例不支持 JSON.stringify

  2. 实例化要求:必须通过new操作符创建实例

  3. 兼容性限制:

  4. 禁止与 V1 装饰器(如 @State、@Observed)混用

  5. 继承自 @ObservedV2 的类不可与 V1 装饰器共用

  6. 数组处理:仅支持基础类型数组的标准 API 操作(如 push/splice)

案例

没有使用 @observedv2 和 @trace 装饰器的时候,如果想更新 UI,需要 @local 配合新创建对象。


下面案例两个按钮点击的时候重新 new 了 student 对象,才引起了 UI 刷新,如果单独修改属性则不会引起刷新。



class Student{ name:string  age:number
constructor(name: string, age: number) { this.name = name; this.age = age; }
}
@Entry@ComponentV2struct Observerpage { // @local装饰只会观察到对象引用的变化 @Local student:Student=new Student('gxx',20)
build() { Column({space:20}){ Button('姓名: '+this.student.name) .width('60%') .onClick(()=>{ // 更新对象可以引起UI刷新 this.student=new Student('ggl',30) // 不会引起UI刷新,@local观察不到属性的变化 this.student.name='ggl' }) Button('年龄: '+this.student.age) .width('60%') .onClick(()=>{ // 更新对象可以引起UI刷新 this.student=new Student('xyz',33) }) } .height('100%') .width('100%') }}
复制代码


有使用 @observedv2 和 @trace 装饰器的时候,如果想更新 UI,不需要 @local 装饰器,可以直接更新属性即可。


下面案例中 name 被 @Trace 装饰,age 没有被 @Trace 装饰,student 没有被 @local 装饰,所以更新对象的时候不会引起刷新,name 更新的时候会刷新,age 更新则不会刷新。



@ObservedV2class Student{@Trace name:string  age:number
constructor(name: string, age: number) { this.name = name; this.age = age; }
}
@Entry@ComponentV2struct Observerpage1 { // 不需要@local 都可以观察到属性的变化 但是无法观察对象的变化 student:Student=new Student('gxx',20)
build() { Column({space:20}){ Button('姓名: '+this.student.name) .width('60%') .onClick(()=>{ // 更新对象无法可以引起UI刷新 因为没有@local装饰 // this.student=new Student('ggl',30) // 会引起UI刷新,属性被@Trace装饰 this.student.name='ggl' }) Button('年龄: '+this.student.age) .width('60%') .onClick(()=>{ // 不会引起UI刷新 没有被@Trace装饰 this.student.age+=10 }) } .height('100%') .width('100%') }}
复制代码


嵌套类的情况:


下面案例里面 user 嵌套了 address,我们需要给两个类都加 @observedv2 装饰器,user 里面的 name 需要加 @trace 而 address 嵌套类里面已经有 @trace 装饰,则本身不用 @trace 装饰了。



@ObservedV2class Address {  @Trace city: string;
constructor(city: string) { this.city = city; }
}
@ObservedV2class User { @Trace name: string; address: Address; //这里即使不加@Trace也会被观察到 嵌套类属性变化可触发UI刷新 constructor(name: string, address: Address) { this.name = name; this.address = address; }
}
@Entry@ComponentV2struct Observerpage2 { // 不需要@local 都可以观察到属性的变化 但是无法观察对象的变化 addr:Address=new Address('商丘') u:User=new User('gxx',this.addr) build() { Column({space:20}){ Button('姓名: '+this.u.name) .width('60%') .onClick(()=>{ // 会引起UI刷新,属性被@Trace装饰 this.u.name='ggl' }) Button('地址: '+this.u.address.city) .width('60%') .onClick(()=>{ // 会引起UI刷新 this.u.address.city='郑州' }) } .height('100%') .width('100%') }}
复制代码


类继承的情况:


下面案例里面 dog 类继承了 animal,dog 类里面的属性就有了 animal 中的属性,并且都由 @Trace 装饰,所以属性更新会引起 UI 更新。



@ObservedV2class Animal {  @Trace age: number;
constructor(age: number) { this.age = age; }}@ObservedV2class Dog extends Animal { @Trace breed: string; // 继承类属性变化可触发UI刷新
constructor(age: number, breed: string) { super(age); this.breed = breed; }}
@Entry@ComponentV2struct Observerpage3 { // 不需要@local 都可以观察到属性的变化 但是无法观察对象的变化 dog:Dog=new Dog(18,'哈士奇') build() { Column({space:20}){ Button('年龄: '+this.dog.age) .width('60%') .onClick(()=>{ // 会引起UI刷新,继承过来的 this.dog.age=10 }) Button('品种: '+this.dog.breed) .width('60%') .onClick(()=>{ // 会引起UI刷新 属性被@Trace装饰 this.dog.breed='藏獒' }) } .height('100%') .width('100%') }}
复制代码


发布于: 刚刚阅读数: 6
用户头像

高心星

关注

天将降大任于斯人也,必先苦其心志。 2024-10-17 加入

华为开发者专家(HDE)。 10年教学经验,兼任多家科技公司技术顾问。先后从事JavaEE项目开发、Python爬虫、HarmonyOS移动应用开发等课程的教学工作。参与开发《鸿蒙应用开发基础》和《鸿蒙项目实战》等课程。

评论

发布
暂无评论
鸿蒙5.0应用开发——V2装饰器@ObservedV2和@Trace的使用_鸿蒙_高心星_InfoQ写作社区