写点什么

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

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

    阅读完需:约 10 分钟

鸿蒙5.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 的对比。



  1. 深度监听能力

  2. 支持监听嵌套类、多维数组、对象数组中指定项的变化(需配合 @ObservedV2 和 @Trace 使用)

  3. 示例场景:监听用户信息对象中address.city属性的变化,仅当该属性修改时触发回调

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


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


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

Imonitor 接口说明

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


一、IMonitor 核心功能


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


   @Monitor('users.0.name', 'users.1.age')   onChanges(monitor: IMonitor) {     monitor.dirty.forEach((path: string) => {       console.log(`路径 ${path} 发生变化`);     });   }
复制代码


  1. 值变化对比monitor.value(path) 返回一个包含 beforenow 属性的对象,用于获取变化前后的值:


   const change = monitor.value('dimensionTwo.0.0');   console.log(`旧值:${change?.before} → 新值:${change?.now}`);
复制代码


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

案例

monitor 的基本使用:


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



@Entry@ComponentV2struct 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 才能观察到属性的变化。



@ObservedV2class user{ @Trace name:string @Trace age:number
constructor(name: string, age: number) { this.name = name this.age = age }
}
@Entry@ComponentV2struct 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 将要观察的是数组元素和数组长度的变化。



@Entry@ComponentV2struct 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%') }}
复制代码


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

高心星

关注

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

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

评论

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