# 14.9:@Monitor

ArkUI 开发框架提供了 @Monitor 装饰器来监听状态变量的修改,使得状态变量具有深度监听的能力,本节笔者简单介绍一下 @Monitor 的使用。

# 14.9.1:约束与限制

  • @Monitor 只支持 @Local@Param@Provider@Consumer 装饰的变量。
  • @Monitor 允许在 @ObserverV2 的类内使用来监听 @Trace 装饰的变量。
  • @Monitor 在继承类场景中,父子类同时监听同一个属性则会同时回调监听函数。

# 14.9.2:语法介绍

@Monitor 装饰器可以接收一个或多个装饰器参数,这些参数为状态属性名,中间用逗号隔开,然后装饰一个方法,并且要求该方法仅接收一个 IMonitor 类型的参数,格式为: @Monitor("attribute1", "attribute2", ..., "attributeN") function_name(monitor: IMonitor),样例如下所示:

@Entry @ComponentV2 struct Page_state {

  @Local userName: string = ""               // 定义状态变量userName

  @Monitor("userName")                       // 使用@Monitor监听userName,如果userName变化了则执行notifyUserNameChanged()方法
  notifyUserNameChanged(monitor: IMonitor) { // IMonitor包含了状态属性前后变化值和属性名
  }

  build() {
  }

}
1
2
3
4
5
6
7
8
9
10
11
12

# 14.9.3:简单样例

@Monitor 的简单样例如下所示:

import { promptAction } from '@kit.ArkUI'

@Entry @ComponentV2 struct Page_state {

  @Local userName: string = "张三"           // 定义状态变量userName

  @Monitor("userName")                      // 监听状态变量userName
  notifyUserNameChanged(monitor: IMonitor) {
    monitor.dirty.forEach((name) => {
      let before = monitor.value(name)?.before as string
      let now = monitor.value(name)?.now as string
      promptAction.showToast({
        message: "之前: " + before + ", 现在: " + now,
        alignment: Alignment.Top
      })
    })

  }

  build() {
    Column({space: 20}) {
      Text(this.userName)
      Button("更改用户名")
        .onClick(() => {
          this.userName = "李四:" + new Date().getMilliseconds();
        })
    }
    .width("100%")
  }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

样例运行结果如下图所示:

14_9_3_1

# 14.9.4:使用场景

  • 多属性监听

    @Monitor 支持同时监听多个状态属性,简单样例如下所示:

    import { promptAction } from '@kit.ArkUI'
    
    @Entry @ComponentV2 struct Page_state {
    
      @Local userName: string = "张三"
      @Local address: string = "北京"
      @Local birthday: string = "2020"
    
      @Monitor("userName", "address", "birthday")
      notifyUserNameChanged(monitor: IMonitor) {
        monitor.dirty.forEach((name) => {
          let before = monitor.value(name)?.before as string
          let now = monitor.value(name)?.now as string
          promptAction.showToast({
            message: "之前: " + before + ", 现在: " + now,
            alignment: Alignment.Top
          })
        })
    
      }
    
      build() {
        Column({space: 20}) {
          Text(this.userName + ", " + this.address + ", " + this.birthday)
          Row({space: 10}) {
            Button("更改姓名")
              .onClick(() => {
                this.userName = "李四:" + new Date().getMilliseconds();
              })
            Button("更改住址")
              .onClick(() => {
                this.address = "北京:" + new Date().getMilliseconds();
              })
            Button("更改生日")
              .onClick(() => {
                this.birthday = "2020:" + new Date().getMilliseconds();
              })
          }
        }
        .width("100%")
      }
    
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43

    样例运行结果如下图所示:

    14_9_4_1
  • 类对象监听

    @Monitor支持监听状态对象,也就是说只支持对状态对象本身赋值操作做监听,简单样例如下所示:

    import { promptAction } from '@kit.ArkUI'
    
    class User {
      userName: string;
      address: string;
    
      constructor(userName: string, address: string) {
        this.userName = userName;
        this.address = address;
      }
    }
    
    @Entry @ComponentV2 struct Page_state {
    
      @Local user: User = new User("张三", "北京")
    
      @Monitor("user")
      notifyUserNameChanged(monitor: IMonitor) {
        monitor.dirty.forEach((name) => {
          let before = JSON.stringify(monitor.value(name)?.before)
          let now = JSON.stringify(monitor.value(name)?.now)
          promptAction.showToast({
            message: "之前: " + before + ", 现在: " + now,
            alignment: Alignment.Top
          })
        })
    
      }
    
      build() {
        Column({space: 20}) {
          Text("用户:" + this.user.userName + ", " + this.user.address)
          Row({space: 10}) {
            Button("更改用户")
              .onClick(() => {
                this.user = new User("李四", "上海"); // Text刷新
              })
            Button("更改姓名")
              .onClick(() => {
                this.user.userName = "王五"          // Text不变
              })
          }
        }
        .width("100%")
      }
    
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47

    样例运行结果如下图所示:

    14_9_4_2
  • 多层次监听

    @Monitor支持监听状态对象内被@Trace修饰的属性,简单样例如下所示:

    import { promptAction } from '@kit.ArkUI'
    
    @ObservedV2
    class User {
    
      @Trace
      userName: string;
      @Trace
      address: string;
    
      constructor(userName: string, address: string) {
        this.userName = userName;
        this.address = address;
      }
    }
    
    @Entry @ComponentV2 struct Page_state {
    
      @Local user: User = new User("张三", "北京") // 定义状态属性
    
      @Monitor("user", "user.userName")           // 监听状态,注意监听状态对象的状态属性的写法
      notifyUserNameChanged(monitor: IMonitor) {  // 监听回调
        monitor.dirty.forEach((name) => {
          let before = JSON.stringify(monitor.value(name)?.before)
          let now = JSON.stringify(monitor.value(name)?.now)
          promptAction.showToast({
            message: "之前: " + before + ", 现在: " + now,
            alignment: Alignment.Top
          })
        })
    
      }
    
      build() {
        Column({space: 20}) {
          Text("用户:" + this.user.userName + ", " + this.user.address)
          Row({space: 10}) {
            Button("更改用户")
              .onClick(() => {
                this.user = new User("李四", "上海"); // 可以监听
              })
            Button("更改姓名")
              .onClick(() => {
                this.user.userName = "王五"          // 可以监听
              })
          }
        }
        .width("100%")
      }
    
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51

    简单样例如下图所示:

    14_9_4_3

    📢:监听状态类对象的属性时,注意属性名的写法。

  • 多继承监听

    @Monitor在继承类场景下,可以在继承链中对同一个属性进行多次监听,简单样例如下所示:

    @ObservedV2 class Base {
      @Trace userName: string;
    
      constructor(userName: string) {
        this.userName = userName;
      }
    
      @Monitor("userName")
      notifyUserNameChangedInBase(monitor: IMonitor) {
        console.log("notifyUserNameChangedInBase: " + JSON.stringify(monitor))
      }
    
    }
    
    @ObservedV2 class Parent extends Base {
      constructor(userName: string) {
        super(userName);
      }
    
      @Monitor("userName")
      notifyUserNameChangedInParent(monitor: IMonitor) {
        console.log("notifyUserNameChangedInParent: " + JSON.stringify(monitor))
      }
    }
    
    @ObservedV2 class User extends Parent {
    
      @Trace
      address: string;
    
      constructor(userName: string, address: string) {
        super(userName);
        this.address = address;
      }
    
      @Monitor("userName")
      notifyUserNameChangedInUser(monitor: IMonitor) {
        console.log("notifyUserNameChangedInUser: " + JSON.stringify(monitor))
      }
    }
    
    @Entry @ComponentV2 struct Page_state {
    
      @Local user: User = new User("张三", "北京") // 定义状态属性
    
      build() {
        Column({space: 20}) {
          Text("用户:" + this.user.userName + ", " + this.user.address)
          Row({space: 10}) {
            Button("更改用户")
              .onClick(() => {
                this.user = new User("李四", "上海");
              })
            Button("更改姓名")
              .onClick(() => {
                this.user.userName = "王五"          // 可以监听
              })
          }
        }
        .width("100%")
      }
    
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63

    样例运行结果如下图所示:

    14_9_4_3

    点击 更改姓名 按钮,控制台日志打印如下:

    14_9_4_5
请作者喝杯咖啡

津公网安备 12011402001367号

津ICP备2020008934号-2

中央网信办互联网违法和不良信息举报中心

天津市互联网违法和不良信息举报中心