鸿蒙6.0应用开发——V2装饰器@Monitor的使用

【高心星出品】

V2装饰器@Monitor的使用

概念

为了增强状态管理框架对状态变量变化的监听能力,开发者可以使用@Monitor装饰器对状态变量进行监听。

@Monitor装饰器用于监听状态变量修改,使得状态变量具有深度监听的能力:

  • @Monitor装饰器支持在@ComponentV2装饰的自定义组件中使用,未被状态变量装饰器@Local、@Param、@Provider、@Consumer、@Computed装饰的变量无法被@Monitor监听到变化。
  • @Monitor装饰器支持在类中与@ObservedV2、@Trace配合使用,不允许在未被@ObservedV2装饰的类中使用@Monitor装饰器。未被@Trace装饰的属性无法被@Monitor监听到变化。
  • 当观测的属性变化时,@Monitor装饰器定义的回调方法将被调用。判断属性是否变化使用的是严格相等(===),当严格相等判断的结果是false(即不相等)的情况下,就会触发@Monitor的回调。当在一次事件中多次改变同一个属性时,将会使用初始值和最终值进行比较以判断是否变化。
  • 单个@Monitor装饰器能够同时监听多个属性的变化,当这些属性在一次事件中共同变化时,只会触发一次@Monitor的回调方法。
  • @Monitor装饰器具有深度监听的能力,能够监听嵌套类、多维数组、对象数组中指定项的变化。对于嵌套类、对象数组中成员属性变化的监听要求该类被@ObservedV2装饰且该属性被@Trace装饰。
  • 当@Monitor监听整个数组时,更改数组的某一项不会被监听到。无法监听内置类型(Array、Map、Date、Set)的API调用引起的变化。
  • 在继承类场景中,可以在父子组件中对同一个属性分别定义@Monitor进行监听,当属性变化时,父子组件中定义的@Monitor回调均会被调用。
  • 和@Watch装饰器类似,开发者需要自己定义回调函数,区别在于@Watch装饰器将函数名作为参数,而@Monitor直接装饰回调函数。@Monitor与@Watch的对比可以查看@Monitor与@Watch的对比。
特性 @Monitor @Watch
监听深度 支持深层属性监听 仅第一层属性监听
多属性监听 支持同时监听多个属性 仅支持单个属性监听
新旧值获取 提供变化前后的完整值 无法获取旧值
回调触发机制 多属性同事件变化合并触发 每个属性变化独立触发
类属性监听 需配合@ObservedV2和@Trace 不支持类属性监听
  1. 深度监听能力

    • 支持监听嵌套类、多维数组、对象数组中指定项的变化(需配合@ObservedV2和@Trace使用)
    • 示例场景:监听用户信息对象中address.city属性的变化,仅当该属性修改时触发回调
  2. 多属性联合监听

    可同时监听多个属性变化,当多个属性在一次事件中共同变化时,仅触发一次回调:

    typescript 复制代码
    @Monitor('age', 'height')
    onRecordChange(monitor: IMonitor) {
      console.log(`年龄或身高变化:${this.age}, ${this.height}`);
    }
  3. 变化值追踪

    提供变化前后的值对比能力,通过monitor.value()?.beforemonitor.value()?.now访问新旧值

Imonitor接口说明

在鸿蒙ArkTS状态管理V2中,IMonitor 是配合 @Monitor 装饰器使用的核心接口,用于捕获和响应状态变量的细粒度变化。以下是关键特性和用法解析:


一、IMonitor 核心功能

  1. 变化路径追踪

    通过 monitor.dirty 获取所有触发回调的变量路径集合,适用于同时监听多个路径的场景:

    typescript 复制代码
    @Monitor('users.0.name', 'users.1.age')
    onChanges(monitor: IMonitor) {
      monitor.dirty.forEach((path: string) => {
        console.log(`路径 ${path} 发生变化`);
      });
    }
  2. 值变化对比
    monitor.value(path) 返回一个包含 beforenow 属性的对象,用于获取变化前后的值:

    typescript 复制代码
    const change = monitor.value('dimensionTwo.0.0');
    console.log(`旧值:${change?.before} → 新值:${change?.now}`);
  3. 路径动态解析

    支持多维数组和嵌套对象路径(如 array.0.property),要求路径必须与被 @Trace 装饰的属性严格匹配。

案例

monitor的基本使用:

下面案例monitor观察两个基本变量,当两个变量改变的时候,显示旧数据和新数据。

typescript 复制代码
@Entry
@ComponentV2
struct Monitorpage {
  // 被观察的数据必须由@local @param或者@provider装饰
  @Local name: string = 'gxx'
  @Local age: number = 30
  @Local msg:string=''
  // 观察的变量要一一列举
  @Monitor('name','age')
  // Imonitor 中的dirty代表改变的变量名字,类型为数组
  // Imonitor 中的value代表该dirty对应的数据,包含旧数据和新数据
  ondatachange(data: IMonitor) {
    data.dirty.forEach((item: string) => {
      let before = data.value(item)?.before!
      let after = data.value(item)?.now!
     this.msg+=`${item} 旧数据:${before} 新数据:${after}\n`
    })
  }

  build() {
    Column({ space: 20 }) {
      Button('page name: ' + this.name)
        .width('60%')
        .onClick(() => {
          // 同时改变name和age
          this.name = 'ggl'
          this.age += 1
        })
      Button('page age: ' + this.age)
        .width('60%')
        .onClick(() => {
          this.age += 1
        })
      Text(this.msg).fontSize(20)
    }
    .height('100%')
    .width('100%')
  }
}

monitor观察复杂对象:

下面案例monitor观察的数据是复杂对象,需要使用@observed才能观察到属性的变化。

typescript 复制代码
@ObservedV2
class user{
 @Trace name:string
 @Trace age:number

  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }

}

@Entry
@ComponentV2
struct Monitorpage {
  // 被观察的数据必须由@local @param或者@provider装饰
  @Local u: user = new user('gxx',30)
  @Local msg:string=''
  // 观察对象U 属性改变不会引起刷新
  @Monitor('u.name','u.age')
  // Imonitor 中的dirty代表改变的变量名字,类型为数组
  // Imonitor 中的value代表该dirty对应的数据,包含旧数据和新数据
  ondatachange(data: IMonitor) {
    data.dirty.forEach((item: string) => {
      let before = data.value(item)?.before!
      let after = data.value(item)?.now!
     this.msg+=`${item} 旧数据:${before} 新数据:${after}\n`
    })
  }

  build() {
    Column({ space: 20 }) {
      Button('page name: ' + this.u.name)
        .width('60%')
        .onClick(() => {
          // 同时改变name和age
          this.u.name = 'ggl'
          this.u.age += 1
        })
      Button('page age: ' + this.u.age)
        .width('60%')
        .onClick(() => {
          this.u.age += 1
        })
      Text(this.msg).fontSize(20)
    }
    .height('100%')
    .width('100%')
  }
}

monitor观察数组元素和数组长度案例:

下面这个案例monitor将要观察的是数组元素和数组长度的变化。

typescript 复制代码
@Entry
@ComponentV2
struct Monitorpage {
  // 被观察的数据必须由@local @param或者@provider装饰
  @Local nums:number[]=[1,2,3]
  @Local msg:string=''
  // 观察数组nums的元素nums.i和数组长度 nums.length
  @Monitor('nums.0','nums.length')
  // Imonitor 中的dirty代表改变的变量名字,类型为数组
  // Imonitor 中的value代表该dirty对应的数据,包含旧数据和新数据
  ondatachange(data: IMonitor) {
    data.dirty.forEach((item: string) => {
      let before = data.value(item)?.before!
      let after = data.value(item)?.now!
     this.msg+=`${item} 旧数据:${before} 新数据:${after}\n`
    })
  }

  build() {
    Column({ space: 20 }) {
      Button('page nums.0: ' + this.nums[0])
        .width('60%')
        .onClick(() => {
          // 新增元素
          this.nums[0]=this.nums[0]+1
          this.nums.push(this.nums[this.nums.length-1]+1)
        })
      Button('page nums.1: ' + this.nums[1])
        .width('60%')
        .onClick(() => {
          // 更新数据
          this.nums[1]=10
        })
      Text(this.msg).fontSize(20)
    }
    .height('100%')
    .width('100%')
  }
}
相关推荐
海市公约1 天前
Python三大高阶特性详解:装饰器、生成器与上下文管理器
装饰器·生成器·yield·高阶函数·python进阶·with语句·上下文管理器
耿雨飞6 天前
Python 后端开发技术博客专栏 | 第 02 篇 函数式编程与 Python 魔法 -- 闭包、装饰器、高阶函数
开发语言·python·装饰器·高阶函数·闭包
高心星7 天前
鸿蒙6.0应用开发——基础动画实践案例
华为·动画·鸿蒙6.0·harmonyos6.0·水波动画·微动画·手势动画
高心星13 天前
鸿蒙6.0应用开发——Tabs滑动动画
华为·动画·tabs·鸿蒙6.0·harmonyos6.0
高心星17 天前
鸿蒙6.0应用开发——切换主题
主题·theme·皮肤·鸿蒙6.0·harmonyos6.0
高心星17 天前
鸿蒙6.0应用开发——图片合成视频
视频·图片处理·图片合成视频·鸿蒙6.0·harmonyos6.0
高心星17 天前
鸿蒙6.0应用开发——图文混排
arkui·图文混排·鸿蒙6.0·harmonyos6.0
高心星21 天前
鸿蒙6.0应用开发——定位功能的实现
华为·定位功能·鸿蒙6.0·harmonyos6.0·鸿蒙定位
高心星21 天前
鸿蒙6.0应用开发——自定义键盘的实现
键盘·自定义键盘·鸿蒙6.0·harmonyos6.0·键盘布局
高心星22 天前
鸿蒙6.0应用开发——模块化设计选型:HAP、HAR、HSP?
鸿蒙系统·har·hsp·技术选型·hap·harmonyos6.0·鸿蒙模块化设计