鸿蒙(HarmonyOS)-- 装饰器(状态装饰器V2版本)

本篇文章详细介绍了V2版本状态类装饰器,及其使用方法。V1版本(状态装饰器V1版本)状态类装饰器请移步上期文章(状态装饰器V1版本)

目录

1、@Local装饰器:组件内部状态

1.1 基础使用 

1.2 不接受外来赋值

1.3 观测变化 

1.3.1 基本数据类型观测变化

1.3.2 对象数据类型观测变化 

1.3.3 数组数据类型观测变化 

1.3.4 其他内置数据类型观测变化 

2、@Param:组件外部输入

 2.1 基础使用

2.2 配合@Require使用

 3、@Event 装饰器:规范组件输出

3.1 修改@Param装饰的数据 

4、@Once:初始化同步一次

4.1 基础使用 

4.2 当前组件内修改

5、@ObservedV2装饰器和@Trace装饰器:类属性变化观测 

 6、@Provider装饰器和@Consumer装饰器:跨组件层级双向同步

6.1 @Provider和@Consumer VS @Provide和@Consume能力对比 

6.2 @Provider和@Consumer装饰复杂类型,配合@Trace一起使用

7、@Computed装饰器:计算属性 

8、@Monitor装饰器:状态变量修改监听

8.1 基础使用 

 8.2 @Monitor 在 @ObservedV2 中使用

 8.4 @Monitor回调函数的参数


1、@Local装饰器:组件内部状态

@Local 装饰器是用来在 V2 组价中定义状态变量, 已达到观测变量的目的( 响应式效果 )。
其作用类似于 V1 版本的 @State【 注:但也只是类似,不一样的地方还是很多的 】

1.1 基础使用 

基本使用来说,和 @State 是一样的,定义状态变量。在 UI 部分使用的时候,一旦状态变量发生变化,UI 会被刷新

【 注:定义简单数据类型,和 @State 没有区别

@Entry
@ComponentV2
struct Index {

  // 使用 @Local 定义状态变量
  @Local message: string = 'hello world'

  build() {
    Column({ space: 10 }) {
      Text('我是 V2 版本自定义组件')

      Text(this.message)

      Button('Change').onClick(() => this.message = '你好 世界')
    }
  }
}

1.2 不接受外来赋值

@Local 不接受外来赋值。

V1 版本

  • 在子组件内使用 @State 定义的状态变量,可以在父组件调用的时候对其进行赋值,覆盖原有初始值

V2 版本 

  • 在子组件内使用 @Local 定义的状态变量,不可以在父组件调用的时候对其进行赋值任何外来数据都不能对 @Local 定义的状态变量进行赋值
@Entry
@ComponentV2
struct Index {

  @Local message: string = 'hello world'

  build() {
    Column({ space: 10 }) {
      Text('我是 Index 组件')

      // 调用子组件的时候, 对子组件内 @Local 定义的 str 进行赋值
      // 此时代码调用会报错
      Child({ str: '从父组件赋值' })
    }
  }
}

@ComponentV2
struct Child {

  @Local str: string = ''

  build() {
    Column() {
      Text('我是 Child 组件')
      Text(this.str)
    }

  }
}

1.3 观测变化 

1.3.1 基本数据类型观测变化

对于基本数据类型来说,和 @State 一样,可以观测到数据赋值的变化。

@Entry
@ComponentV2
struct Index {

  // 使用 @Local 定义状态变量
  @Local message: string = 'hello world'

  build() {
    Column({ space: 10 }) {
      Text('我是 V2 版本自定义组件')

      Text(this.message)

      // 直接修改状态变量的值【 可以观测到变化,引起 UI 刷新 】
      Button('Change').onClick(() => this.message = '你好 世界')
    }
  }
}

1.3.2 对象数据类型观测变化 

对于对象数据类型来说【 { name: '张三', age: 18 } 】

  • 如果直接修改对象本身, 可以观测到变化, 引起 UI 刷新
  • 如果修改的是对象成员的话, 观测不到变化, 不会引起 UI 刷新
class InfoType {
  name: string
  age: number

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

@Entry
@ComponentV2
struct Index {

  // @Local 定义的是对象数据类型
  @Local info: InfoType = new InfoType('张三', 18)

  build() {
    Column({ space: 10 }) {
      Text('我是 Index 组件')

      Text(`
        展示一下对象信息
        name => ${ this.info.name }
        age => ${ this.info.age }
      `)

      // 相当于直接修改 @Local 定义的变量 info, 可以观测到变化【 会引起 UI 刷新 】
      Button('修改对象本身').onClick(() => this.info = new InfoType('李四', 20))

      // 修改对象内的成员, 观测不到变化【 不会引起 UI 刷新 】
      Button('修改对象成员').onClick(() => this.info.age++)
    }
  }
}

如果想要观测到对象成员的变化, 需要配合 @ObservedV2@Trace 装饰器使用才可以

@ObservedV2 是 class 的装饰器

@Trace 是对 class 内属性的装饰器

@Trace 装饰了哪个属性,,哪个属性的修改就可以被观测到

@ObservedV2
class InfoType {
  name: string
  // age 属性被修改的时候就可以被观测到
  @Trace age: number

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

@Entry
@ComponentV2
struct Index {

  @Local info: InfoType = new InfoType('张三', 18)

  build() {
    Column({ space: 10 }) {
      Text('我是 Index 组件')

      Text(`
        展示一下对象信息
        name => ${ this.info.name }
        age => ${ this.info.age }
      `)

      Button('修改对象本身').onClick(() => this.info = new InfoType('李四', 20))
      
  		// 当对象内的 age 属性被修改的时候, 就可以观测到, 会引起 UI 刷新
      Button('修改对象成员').onClick(() => this.info.age++)
      
      // 当对象内的 name 属性被修改的时候, 不可以被观测到, 不会引起 UI 刷新(因为没有被@Trace装饰)
      Button('修改对象成员').onClick(() => this.info.name = '王五')
    }
  }
}

1.3.3 数组数据类型观测变化 

对于数组数据类型来说

  • 如果数组内存储的都是基本数据类型
  • 不管是一维数组还是二维数组
  • 不管是修改数组整体还是修改数组项

都可以观测到变化, 会引起 UI 刷新

@Entry
@ComponentV2
struct Index {

  // 定义数组【 不管一维还是二维, 内部数据一定是基本数据类型 】
  @Local list1: number[] = [ 1, 2, 3 ]
  @Local list2: number[][] = [ [1, 2], [3, 4] ]

  build() {
    Column({ space: 10 }) {
      Text('我是 Index 组件')

      Text(`
        展示一下数组信息
        list1 =>
              => ${ this.list1[0] }
              => ${ this.list1[1] }
              => ${ this.list1[2] }
        list2 =>
              => ${ this.list2[0][0] }
              => ${ this.list2[0][1] }
              => ${ this.list2[1][0] }
              => ${ this.list2[1][1] }
      `)
      // 不管修改哪一个数组项中的数据,都可以观测到变化,并触发UI刷新
      Button('修改 list1 数组项').onClick(() => this.list1[0]++)
      Button('修改 list2 数组项数据').onClick(() => this.list2[0][1]++)
    }
  }
}

如果数组内存储的都是对象数据类型

不管一维还是二维数组

直接修改数组项成员(对象), 是可以观测到变化的, 引起 UI 刷新

如果修改的是对象内的属性, 是不能观测到变化的, 不会引起 UI 刷新

class InfoType {
  name: string
  age: number

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

@Entry
@ComponentV2
struct Index {

  @Local list1: InfoType[] = [new InfoType('张三', 18), new InfoType('李四', 20)]
  @Local list2: InfoType[][] = [
    [new InfoType('张三', 18), new InfoType('李四', 20)],
    [new InfoType('王五', 22), new InfoType('赵六', 24)]
  ]

  build() {
    Column({ space: 10 }) {
      Text('我是 Index 组件')

      Text(`
        展示一下数组信息
        list1 =>
              => ${ this.list1[0].name } - ${ this.list1[0].age }
              => ${ this.list1[1].name } - ${ this.list1[1].age }
        list2 =>
              => ${ this.list2[0][0].name } - ${ this.list2[0][0].age }
              => ${ this.list2[0][1].name } - ${ this.list2[0][1].age }
              => ${ this.list2[1][0].name } - ${ this.list2[1][0].age }
              => ${ this.list2[1][1].name } - ${ this.list2[1][1].age }
      `)
      
      // 直接修改对象,可以观测到变化,并触发UI刷新。
      Button('修改 list1 数组项').onClick(() => this.list1[0] = new InfoType('小红', 100))
      Button('修改 list2 数组项数据').onClick(() => this.list2[0][1] = new InfoType('小明狼', 100))

      // 修改对象成员(属性),不能观测到变化,不会触发UI刷新。
      // 如果想要实现修改对象成员也可以观测到
      // 和对象数据类型是一样的, 需要用 @ObservedV2 和 @Trace 装饰器
      Button('修改 list1 数组项').onClick(() => this.list1[0].age++)
      Button('修改 list2 数组项数据').onClick(() => this.list2[0][1].age++)
    }
  }
}

1.3.4 其他内置数据类型观测变化 

对于其他数据结构来说【 Date,Set,Map,。。。 】

调用内置 API 修改数据是可以观测到变化的

比如 Date

  • 调用 setFullYear(), setMonth(), setHours, ... 改变 Date 的值, 是可以观测到的

其他内置数据结构也是如此 

2、@Param:组件外部输入

@Param 是专门在子组件内使用,用于接受外部传入的数据。因为在使用 @Local 的时候, 不能接收外部传入的数据,所以这里使用 @Param 装饰器。

【注意:】

  • @Param 不光可以接收外部数据, 还可以接收 @Local 的同步变化
  • 单独使用 @Param 是必须要在初始化时候赋值的, 外部传入的时候再进行覆盖
  • 如果想在 @Param 的时候不进行初始化,需要配合 @Require 装饰器一起使用
  • @Param 装饰的数据是只读的,不可以修改,如果修改的话需要配合 @Event 装饰器
  • 对于观测数据变化,和 @Local 规则是一样的

 2.1 基础使用

【 注:在 Child 组件内不能修改 str 的值,因为@Param装饰的变量是只读的,需要配合@Event装饰器修改】

@Entry
@ComponentV2
struct Index {

  @Local message: string = 'hello world'

  build() {
    Column({ space: 10 }) {
      Text('我是 Index 组件')

      // 调用子组件的时候可以不给子组件内的 str 赋值
      Child()

      // 调用子组件的时候也可以给子组件内的 str 赋值
      Child({ str: '父组件赋值' })
    }
  }
}

@ComponentV2
struct Child {

  // 使用 @Param 定义一个 str 变量
  // 这里必须要给 str 进行一次赋值, 否则报错
  @Param str: string = '子组件初始化默认值'

  build() {
    Column() {
      Text('我是 Child 组件')

      Text(this.str)
    }
  }
}

2.2 配合@Require使用

@Entry
@ComponentV2
struct Index {

  @Local message: string = 'hello world'

  build() {
    Column({ space: 10 }) {
      Text('我是 Index 组件')

      // 因为 Child 子组件内 str 配合了 @Require 装饰器
      // 所以如果没有进行赋值, 会直接报错
      Child() // => 报错

      // 调用子组件的时候也可以给子组件内的 str 赋值
      Child({ str: '父组件赋值' })
    }
  }
}

@ComponentV2
struct Child {

  // 使用 @Param 定义一个 str 变量
  // 配合 @Require 使用的时候, 可以不用进行初始化赋值
  @Require @Param str: string

  build() {
    Column() {
      Text('我是 Child 组件')

      Text(this.str)
    }
  }
}

 3、@Event 装饰器:规范组件输出

@Event 是为了实现子组件向父组件要求更新 @Param 装饰变量的能力。

使用@Event装饰回调方法是一种规范,表明子组件需要传入更新数据源的回调。

@Event 主要配合 @Param 实现数据的双向同步。

因为我们通过 @Param 的学习, 发现 @Param 是单向数据同步

  • 父组件数据变化会引起子组件数据变化
  • 子组件数据变化不会引起父组件数据变化

【注意:】

  • @Event 不能修饰非函数数据
  • @Event 本地可以不初始化或者初始化一个空函数,需要从父组件接受一个函数

3.1 修改@Param装饰的数据 

其实就是通过调用父组件传递过来的方法,修改父组件数据。

@Entry
@ComponentV2
struct Index {

  @Local message: string = 'hello world'

  build() {
    Column({ space: 10 }) {
      Text('我是 Index 组件')

      // 调用子组件的时候也可以给子组件内的 str 赋值
      // 并且传递进去一个函数赋值给 @Event 创建的函数变量
      Child({
        str: this.message,
        changeHandler: (val: string) => {
          this.message = val
        }
      })
    }
  }
}

@ComponentV2
struct Child {

  @Param str: string = ''

  // 定义一个函数用来修改父组件的数据
  @Event changeHandler: (s: string) => void

  build() {
    Column() {
      Text('我是 Child 组件')

      Text(this.str)

      // 当你想在子组件内修改 @Param 定义的数据的时候
      Button('子组件内修改数据').onClick(() => this.changeHandler('你好 世界'))

    }
  }
}

根据上述代码

在 Index(父组件) 内调用 Child(子组件) 的时候, 给 str 和 changeHandler 都进行了赋值

在 Child 组件中, 点击 Button 按钮的时候, 就会触发函数( 该函数是父组件定义传递进来的 )

就会同步修改父组件内的 message 数据

因为 message 数据的修改, 就会同步到 Child 子组件的 str 变量

实现了子组件内数据的修改

【 注:通过调用 @Event 函数通知父组件修改 message 数据是同步的,父组件修改完毕回传回子组件是异步的 】

4、@Once:初始化同步一次

@Once 装饰器仅从外部初始化一次、不接受后续同步变化的能力,你可以使用 @Once 装饰器搭配 @Param 装饰器使用。

只有父组件调用子组件的时候传递参数时赋值一次,后续父组件修改数据,子组件不会同步修改。

【注意:】

@Once 必须和 @Param 搭配在一起使用, 不可以单独使用

@Once 不影响 @Param 观测数据的规则

@Once 配合 @Param 使用的时候,可以在当前组件内直接修改数据

4.1 基础使用 

@Entry
@ComponentV2
struct Index {

  @Local message: string = 'hello world'

  build() {
    Column({ space: 10 }) {
      Text('我是 Index 组件')

      // 调用子组件的时候也可以给子组件内的 str 赋值
      Child({ str: this.message })

      // 在父组件内修改 message 的值,不会同步到 Child 内, 在 Child 组件内不会进行 UI 刷新
      Button('Change').onClick(() => this.message = '你好 世界')
    }
  }
}

@ComponentV2
struct Child {

  // @Once 和 @Param 配合使用定义 str
  @Once @Param str: string = ''

  build() {
    Column() {
      Text('我是 Child 组件')

      Text(this.str)
    }
  }
}

根据上述代码

  • 此时只有在 Index(父组件) 最开始调用 Child(子组件) 的时候进行的赋值是有效的
  • 后期在 Index 组件内修改 message 的值的时候, 不会同步到 Child 内, 在 Child 组件内不会进行 UI 刷新

4.2 当前组件内修改

@Entry
@ComponentV2
struct Index {

  @Local message: string = 'hello world'

  build() {
    Column({ space: 10 }) {
      Text('我是 Index 组件')

      // 调用子组件的时候也可以给子组件内的 str 赋值
      Child({ str: this.message })
    }
  }
}

@ComponentV2
struct Child {

  // @Once 和 @Param 配合使用定义 str
  @Once @Param str: string = ''

  build() {
    Column() {
      Text('我是 Child 组件')

      Text(this.str)

      // 在子组件内自己修改
      Button('Change').onClick(() => this.str = '你好 世界')
    }
  }
}

根据上述代码

  • Child(子组件) 内可以自己修改 str 这个数据的值, 并且可以观测到变化, 会引起 UI 刷新了

其实

  • @Once@Param 配合就等价于 @Local
  • 只不过 @Local不能接收外部数据传递
  • @Once@Param 配合在一起可以接收外部数据【 只能接受一次 】

5、@ObservedV2装饰器和@Trace装饰器:类属性变化观测 

@ObservedV2@Trace提供了对嵌套类对象属性变化直接观测的能力

@ObservedV2装饰Class类

@Trace装饰Class的属性。被@Trace装饰的属性变化时,可以被观测到。

@ObservedV2
class InfoType {
  name: string
  // age 属性被修改的时候就可以被观测到
  @Trace age: number

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

@Entry
@ComponentV2
struct Index {

  @Local info: InfoType = new InfoType('张三', 18)

  build() {
    Column({ space: 10 }) {
      Text('我是 Index 组件')

      Text(`
        展示一下对象信息
        name => ${ this.info.name }
        age => ${ this.info.age }
      `)

      Button('修改对象本身').onClick(() => this.info = new InfoType('李四', 20))
      
  		// 当对象内的 age 属性被修改的时候, 就可以观测到, 会引起 UI 刷新
      Button('修改对象成员').onClick(() => this.info.age++)
      
      // 当对象内的 name 属性被修改的时候, 不可以被观测到, 不会引起 UI 刷新(因为没有被@Trace装饰)
      Button('修改对象成员').onClick(() => this.info.name = '王五')
    }
  }
}

 6、@Provider装饰器和@Consumer装饰器:跨组件层级双向同步

在状态管理V1版本中,提供跨组件层级双向的装饰器为@Provide@Consume,当前文档介绍的是状态管理V2装饰器@Provider@Consumer。虽然两者名字和功能类似,但在特性上还存在一些差异。

@Provider@Consumer用于跨组件层级数据双向同步,可以使得开发者不用拘于组件层级。

@Provider@Consumer属于状态管理V2装饰器,所以只能在@ComponentV2中才能使用,在V1装饰器@Component中使用会编译报错。

6.1 @Provider和@Consumer VS @Provide和@Consume能力对比 

能力

V2装饰器@Provider和@Consumer

V1装饰器@Provide和@Consume

@Consume(r)

允许本地初始化,当找不到@Provider的时候使用本地默认值。

禁止本地初始化,当找不到对应的的@Provide时候,会抛出异常。

支持类型

支持function。

不支持function。

观察能力

仅能观察自身赋值变化,如果要观察嵌套场景,配合@Trace一起使用。

观察第一层变化,如果要观察嵌套场景,配合@Observed和@ObjectLink一起使用。

alias和属性名

alias是唯一匹配的key,如果缺省alias,则默认属性名为alias。

alias和属性名都为key,优先匹配alias,匹配不到可以匹配属性名。

@Provide(r) 从父组件初始化

禁止。

允许。

@Provide(r)支持重载

默认开启,即@Provider可以重名,@Consumer向上查找最近的@Provider。

默认关闭,即在组件树上不允许有同名@Provide。如果需要重载,则需要配置allowOverride。

6.2 @Provider和@Consumer装饰复杂类型,配合@Trace一起使用

  • @Provider和@Consumer只能观察到数据本身的变化。如果当其装饰复杂数据类型,需要观察属性的变化时,需要配合@Trace一起使用。
  • 装饰内置类型:Array、Map、Set、Date时,可以观察到某些API的变化,观察能力同@Trace
@ObservedV2
class User {
  @Trace name: string;
  @Trace age: number;

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

const data: User[] = [new User('Json', 10), new User('Eric', 15)];
@Entry
@ComponentV2
struct Parent {
  @Provider('data') users: User[] = data;

  build() {
    Column() {
      Child()
      Button('add new user')
        .onClick(() => {
          this.users.push(new User('Molly', 18));
        })
      Button('age++')
        .onClick(() => {
          this.users[0].age++;
        })
      Button('change name')
        .onClick(() => {
          this.users[0].name = 'Shelly';
        })
    }
  }
}

@ComponentV2
struct Child {
  @Consumer('data') users: User[] = [];

  build() {
    Column() {
      ForEach(this.users, (item: User) => {
        Column() {
          Text(`name: ${item.name}`).fontSize(30)
          Text(`age: ${item.age}`).fontSize(30)
          Divider()
        }
      })
    }
  }
}

7、@Computed装饰器:计算属性 

@Computed装饰器的能力就是提供一个计算属性的能力【 和 Vue 内的计算属性一个道理 】

只有当被计算数据发生变化的时候才会从新计算

主要应用于解决UI多次重用该属性从而重复计算导致的性能问题

@Entry
@ComponentV2
struct Index {

  @Local firstName: string = '张'
  @Local lastName: string = '小明'

  // 定义一个计算属性
  @Computed
  get fullName() {
    return this.firstName + this.lastName
  }

  build() {
    Column({ space: 10 }) {
      Text('我是 Index 组件')

      // 直接使用
      // fullName 的值不能修改,只能是通过修改被计算项( firstName 和 lastName )从而实现重新计算
      Text(this.fullName)
    }
  }
}

8、@Monitor装饰器:状态变量修改监听

@Monitor 装饰器就是监听数据变化的装饰器,类似与 V1 版本里面的 @Watch 装饰器【 但功能强大了很多 】

8.1 基础使用 

在 V1 版本的 @Watch 监听的时候, 只能是一个属性一个属性的监听

  • 每一个要监听的属性都需要写一个 @Watch 装饰器
  • 虽然可以使用同一个回调函数, 但是需要一个变量一个变量的监听

在 V2 版本的 @Monitor 监听的时候

  • 不需要和其他装饰器写在一起,单独使用即可
  • 可以直接确定你需要监听的几个属性
// V1 的 @Watch
@Entry
@Component
struct Index {
  // 每一个属性都需要进行监听
  @State @Watch('changeHandler') message: string = 'hello world'
  @State @Watch('changeHandler') count: number = 10
  @State @Watch('changeHandler2') foo: boolean = true
  
  changeHandler(propertyName: string) {}
  changeHandler2(propertyName: string) {}

  build() {
    Column({ space: 10 }) {
      Text('我是 Index 组件')
    }
  }
}


// V2 的 @Monitor
@Entry
@ComponentV2
struct Index {
  @Local message: string = 'hello world'
  @Local count: number = 10
  @Local foo: boolean = true

  // 设置监听器
  @Monitor('message', 'count', 'foo')
  changeHandler() {}

  build() {
    Column({ space: 10 }) {
      Text('我是 Index 组件')
    }
  }
}

 8.2 @Monitor 在 @ObservedV2 中使用

在 V2 版本中 @Monitor 装饰器不光可以使用在自定义组件中

也可以直接使用在 @ObservedV2 装饰的 class 里面

【 注:在 @ObservedV2 的属性中,被 @Trace 修饰的属性才能监听到变化 】

@ObservedV2
class InfoType {
  @Trace name: string = '小灰狼'
  age: number = 18
  gender: string = '男'
  @Trace score: number = 100

  // 这里可以直接使用 @Monitor 装饰器
  @Monitor('name', 'age')
  changeHandlerOne() {
    console.log('one 触发')
  }

  @Monitor('score', 'gender')
  changeHandlerTwo() {
    console.log('two 触发')
  }
}

@Entry
@ComponentV2
struct Index {

  @Local info: InfoType = new InfoType()

  build() {
    Column({ space: 10 }) {
      Text('我是 Index 组件')

      Button('修改 name').onClick(() => this.info.name = '张三')
      Button('修改 age').onClick(() => this.info.age++)
      Button('修改 gender').onClick(() => this.info.gender = '女')
      Button('修改 score').onClick(() => this.info.score--)
    }
  }
}

 8.3 监听对象属性

@Monitor 装饰器可以直接监听对象内的某一个属性,而不是监控整个对象

@ObservedV2
class InfoType {
  @Trace name: string = '小灰狼'
  age: number = 18
  gender: string = '男'
  @Trace score: number = 100
}

@Entry
@ComponentV2
struct Index {

  @Local info: InfoType = new InfoType()

  // 直接监控对象成员
  @Monitor('info.name')
  changeHandler() {}

  build() {
    Column({ space: 10 }) {
      Text('我是 Index 组件')
      // 只有当 info 内 name 成员变化的时候, 才会触发 changeHandler 回调函数
      Button('修改 name').onClick(() => this.info.name = '张三')
      Button('修改 age').onClick(() => this.info.age++)
      Button('修改 gender').onClick(() => this.info.gender = '女')
      Button('修改 score').onClick(() => this.info.score--)
    }
  }
}

根据上述代码, 可以直接监控 info 对象内的 name 成员

只有当 info 内 name 成员变化的时候, 才会触发 changeHandler 回调函数

【 注:只有被 @Trace 装饰的属性才可以监控到变化,否则监控不到 】

 8.4 @Monitor回调函数的参数

在 V1 版本的 @Watch 监听时,回调函数的参数只有被监控的变量名,而且我们只能拿到改变后的值

在 V2 版本的 @Monitor 监听时,回调函数的参数是一个 IMonitor 对象,可以拿到 属性名、修改之前、修改之后

@ObservedV2
class InfoType {
  @Trace name: string = '小灰狼'
  @Trace age: number = 18
  @Trace gender: string = '男'
  @Trace score: number = 100
}

@Entry
@ComponentV2
struct Index {

  @Local info: InfoType = new InfoType()

  @Monitor('info.name', 'info.age', 'info.gender', 'info.score')
  changeHandler(monitor: IMonitor) { 
    // 利用 IMonitor 参数来拿到 属性名、修改之前、修改之后 的信息
    // 当前修改的属性
    console.log(monitor.value('info.name')?.path)
    // 修改前的值
    console.log(monitor.value('info.name')?.before + '')
    // 修改后的值
    console.log(monitor.value('info.name')?.now + '')
  }

  build() {
    Column({ space: 10 }) {
      Text('我是 Index 组件')

      Button('修改 name').onClick(() => this.info.name = '张三')
      Button('修改 age').onClick(() => this.info.age++)
      Button('修改 gender').onClick(() => this.info.gender = '女')
      Button('修改 score').onClick(() => this.info.score--)
    }
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值