当前位置: 首页 > news >正文

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的规则,从而变成可以被重新赋值的。
    })
  }
}

相关文章:

  • 第一节:React 基础篇-React虚拟DOM原理及Diff算法优化策略
  • 【Web功能测试】注册与登录功能测试用例设计深度解析
  • (十四)安卓开发中的RecyclerView详解
  • Python 和 JavaScript两种语言的相似部分-由DeepSeek产生
  • 计算机操作系统-【死锁】
  • 信奥赛之c++基础(循环结构之for循环)
  • Java常用工具算法-6--秘钥托管云服务3--微软zure Key Vault
  • 第5章,将 Toy IR 程序部分地下降到更低层的 dialect 以便优化
  • 【Grok 大模型深度解析】第二期:架构探秘与训练哲学
  • 在AMGX中使用MPI加载自定义分布式矩阵和向量
  • 自定义函数:为接口开发增添灵活性 - Apipost 的独特优势
  • [特殊字符] 各领域 Dummy 开关实现方式大集合
  • SQL:单表查询基础
  • 面试之《前端信息加密》
  • 使用 Python 扫描 Windows 下的 Wi-Fi 网络实例演示
  • 【Qt】qDebug() << “中文测试“; 乱码问题
  • 论文阅读:2024-arxiv How to Steer LLM Latents for Hallucination Detection?
  • 多坐标系变换全解析:从相机到WGS-84的空间坐标系详解
  • 【Vue】案例——To do list:
  • JS 面向对象编程
  • 简述网站建设的主要内容/网站建设7个基本流程
  • 城建公司建设网站基础资料/快速排名精灵
  • 做网站需要备案吗/汕头网站制作设计
  • 网站建设招标流程图/我也要投放广告
  • 晋中做网站/google关键词seo
  • 做网站怎么查看来访ip/微博推广