HarmonyOS-ArkUI V2装饰器-@Once

前文,关于@Param的使用: HarmonyOS-ArkUIV2装饰器-@Param:组件外部输入-CSDN博客

@Once装饰器是一个需要配合@Param装饰器一块使用的的装饰器。它的特性是,仅仅在变量进行初始化的时候,接受一个外部传来的值进行初始化,然后就不接受后续同步变化了, 当后续数据源进行更改时,不会将修改同步给子组件。它的底层是针对数据源的变化做了拦截操作。

使用方式

我们知道@Param要和@Once一块配合使用,会使得数据只更新一次,但是Param本身而言,它就不能被重新赋值。如果我们拿简单类型的变量来用Param测试,是根本测不到的。因此我们拿@Local作为数据源进行测试。这个可以改动!

复制代码
@Entry
@ComponentV2
struct ParamTest {
  @Local name: string = "name" //注意这里用的是Local修饰,因为我们的测试场景涉及到被重新赋值

  build() {
    Column() {
      Button("change Name")
        .onClick(() => {
          // 随机数计算X Y
          let num1 = Math.floor(Math.random() * 100) + 1;
          let num2 = Math.floor(Math.random() * 100) + 1;
          this.name = `${num1}-${num2}`
        })

      Text(`once值在父组件为:${this.name}`) //这块会正常更新

      // 子组件
      Child({  //在调用子组件的时候就传入其初始化的变量. @Param支持组件间传递数据
        name: this.name
      })
        .margin({ top: 20 })
        .backgroundColor(Color.Orange)
    }
    .height('100%')
    .width('100%')
  }
}

@ComponentV2
struct Child {
  @Param @Once @Require name: string
  build() {
    Column() {
      Text(`name: ${this.name}`) //这块只更新了一次后续数据源再更新它也不更新了
    }
  }
}

注意事项

  • @Once只能和@Param一块使用,如上方代码那样使用

  • @Once是V2版本的装饰器,所以您的组件装饰器一定要是@ComponentV2。

  • @Once的修饰只是表明在组件信息传递上只会接受第一次初始化,而后源数据的变动不再同步。但是并没有说明自己这个值就不能改了。相反,@Param修饰的变量不能被改动,正好被这个@Once装饰器给破掉这个规则了。经由它修饰的变量反而能自己改值。但是改的这个值不会向上层同步给父组件。只是在其组件区域内进行更新。

    @Entry
    @ComponentV2
    struct ParamTest {
    @Local name: string = "name" //注意这里用的是Local修饰,因为我们的测试场景涉及到被重新赋值

    复制代码
    build() {
      Column() {
        Button("change Name")
          .onClick(() => {
            // 随机数计算X Y
            let num1 = Math.floor(Math.random() * 100) + 1;
            let num2 = Math.floor(Math.random() * 100) + 1;
            this.name = `${num1}-${num2}`
          })
    
        Text(`once值在父组件为:${this.name}`) //这块会正常更新
    
        // 子组件
        Child({  //在调用子组件的时候就传入其初始化的变量. @Param支持组件间传递数据
          name: this.name
        })
          .margin({ top: 20 })
          .backgroundColor(Color.Orange)
      }
      .height('100%')
      .width('100%')
    }

    }

    @ComponentV2
    struct Child {
    @Param @Once @Require name: string
    build() {
    Column() {
    Text(name: ${this.name}) //这块只更新了一次后续数据源再更新它也不更新了
    }
    .onClick(() => {
    this.name = "aaaaa" //可以改值
    })
    }
    }
    }

当修饰复杂数据时

修饰复杂类型跟修饰简单类型是两码事哈。只要Once不把这个引用断掉重新赋值, 那么父组件修改了复杂类型的某一个小属性,once是可以更新界面的。但是如果是once修改了属性,其父控件是不更新的。有兴趣的可以试一下下方代码感受:

复制代码
@ObservedV2 //使此类对象具备可观测能力
class Region {
  @Trace x: number //被观测的变量, 这个类型是基本类型
  @Trace y: number //被观测的变量

  constructor(x: number, y: number) {
    this.x = x
    this.y = y
  }
}

class Info {
  region: Region

  constructor(x: number, y: number) {
    this.region = new Region(x, y)
  }
}

@Entry
@ComponentV2
struct ParamTest {
  @Param info: Info = new Info(0, 0)
  @Param onceInfoTest: Info = new Info(1, 1)
  @Local name: string = "name"

  build() {
    Column() {
      Button("Change Region x = " + this.info.region.x)
        .onClick(() => {
          // 随机数计算X Y
          let num1 = Math.floor(Math.random() * 100) + 1;
          let num2 = Math.floor(Math.random() * 100) + 1;
          this.info.region.x = num1
          this.info.region.y = num2

          this.onceInfoTest.region.x += 1 //这个值变化,是用来测试once修饰的复杂类型,是否感知到其中一个属性的变化,从而更新界面。测试结果是可以更新
          this.onceInfoTest.region.y += 1
          this.name = `${num1}-${num2}` //点击的时候Name不断变化,在测试简单类型在子组件是否还更新。这里的操作是重新赋值。
        })

      Text(`父组件 name=:${this.name}`)
        .margin({top: 20})

      // 子组件
      Child({  //在调用子组件的时候就传入其初始化的变量. @Param支持组件间传递数据
        regionObjectLink: this.info.region,
        regionProp: this.info.region,
        infoProp: this.info,
        infoLink: this.info,
        info:  this.onceInfoTest,
        name: this.name
      })
        .margin({ top: 20 })
        .backgroundColor(Color.Orange)
    }
    .height('100%')
    .width('100%')
  }
}

@ComponentV2
struct Child {
  @Param @Require regionObjectLink: Region // 如果Param修饰的变量不进行初始化,预编译就会出问题
  @Param @Require regionProp: Region
  @Param @Require infoProp: Info
  @Param @Require infoLink: Info
  @Param @Once @Require info: Info
  @Param @Once @Require name: string


  build() {
    Column() {
      Text(`ObjectLink region: ${this.regionObjectLink.x}-${this.regionObjectLink.y}`)
      Text(`Prop regionProp: ${this.regionProp.x}-${this.regionProp.y}`)
      Text(`Prop infoProp: ${this.infoProp.region.x}-${this.infoProp.region.y}`)
      Text(`Link infoLink: ${this.infoLink.region.x}-${this.infoLink.region.y}`)
      Text(`Once info: ${this.info.region.x}-${this.info.region.y}`)
      Text(`once 子组件 name: ${this.name}`)
    }
    .onClick(() => {
      this.info.region.x = 200 //这值即使改成200,父组件中界面不更新
      this.info.region.y = 200
      this.name = "aaaaa" //这块代表once修饰的属性,是可以破了param的规则,从而变成可以被重新赋值的。
    })
  }
}
相关推荐
soulermax5 小时前
华为数字芯片机考2025合集2已校正
嵌入式硬件·华为·fpga开发·系统架构·硬件架构
Pigwantofly10 小时前
鸿蒙ArkTS实战:从零打造智能表达式计算器(附状态管理+路由传参核心实现)
android·华为·harmonyos
一只栖枝12 小时前
华为数通不同级别的认证路径和要求是什么?
华为·hcie·hcia·hcip·数通·计算机网络基础·华为实验考试
soulermax12 小时前
华为数字芯片机考2025合集5已校正
华为·fpga开发
绿柱石13 小时前
华为AR1200密码忘记
运维·服务器·华为
蒜白14 小时前
40--华为IPSec VPN实战指南:构建企业级加密通道
华为·网络工程师·ipsec
别说我什么都不会14 小时前
OpenHarmony 实战开发 —— 在自绘编辑框中使用输入法
嵌入式·harmonyos
Georgewu14 小时前
【HarmonyOS 5】鸿蒙实现手写板
前端·华为·harmonyos
御承扬19 小时前
从零开始开发纯血鸿蒙应用之语音输入
华为·harmonyos
rigidwill66620 小时前
华为机试—最大最小路
数据结构·c++·算法·华为od·华为·职场和发展·并查集