鸿蒙开发:V2版本装饰器@Once
前言 本文代码案例基于Api13。 最近准备把refresh刷新库的装饰器由V1升级至V2时,遇到了一个问题,在@Prop装饰器切换@Param装饰器时,发现了自定义组件的属性无法修改问题,提示报错: Cannot assign to 'testContent' because it is a read-only property. 实际错误截图: 错误原因为,@param装饰的变量仅支持本地初始化,不允许在组件内部直接修改变量本身。 虽然知道了原因,但是由于V1版本的逻辑,在自定义组件中除了来自于调用者的传递之外,而自身的属性也需要进行动态修改,否则改动量就很大,正要寻找他法进行实现时,@Once装饰器映入了眼帘。 什么是@Once装饰器 @Once装饰器作为辅助装饰器,本身没有对装饰类型的要求以及对变量的观察能力,但是它具有有两个作用,第一个是解决@Param装饰器修饰后的属性不能修改问题,第二个就是,实现仅从外部初始化一次、不接受后续同步变化的能力,也就是当后续数据源更改时,不会将修改同步给子组件。 有一点需要注意,那就是@Once装饰器不能单独使用,必须 搭配@Param使用,结合使用时,不会影响@Param的观测能力,仅针对数据源的变化做拦截,还有就是谁在前谁在后,这个都不会造成影响。 搭配使用时,前后位置都可以: @Param @Once testContent: string = "测试数据一" @Once @Param testContent2: string = "测试数据一" 使用场景 如果我们仅用 @param装饰进行修饰,会发现,调用者只要数据有改变就会引起自定义组件数据变化,如果你想仅仅初始化进来数据同步一下,之后数据变化无须在同步,那么就可以使用@Once装饰器进行修饰,修饰后,无论怎么修改都不会引起数据变化。 @ComponentV2 struct RefreshLayout { @Param @Once testContent: string = "测试数据一" build() { Column() { Text(this.testContent) } } } @Entry @ComponentV2 struct Index { @Local testContent: string = "Hello World" build() { Column() { RefreshLayout({ testContent: this.testContent }) Button("点击改变") .margin({ top: 20 }) .onClick(() => { this.testContent = "测试数据二" }) }.width("100%") .height("100%") .justifyContent(FlexAlign.Center) } } 上面的情况是外部调用者进行更新,不想引起自定义组件发生数据改变,如果你想在自定义组件内部,使用@Param修饰后的属性,可以发生改变,且能更新UI,那么就可以使用@Once装饰器进行修饰。 @ComponentV2 struct RefreshLayout { @Param @Once testContent: string = "测试数据一" build() { Column() { Text(this.testContent) Button("点击改变") .margin({ top: 20 }) .onClick(() => { this.testContent = "测试数据二" }) } } } @Entry @ComponentV2 struct Index { @Local testContent: string = "Hello World" build() { Column() { RefreshLayout({ testContent: this.testContent }) }.width("100%") .height("100%") .justifyContent(FlexAlign.Center) } } 相关总结 @Once装饰器只能与@Param搭配使用,仅此一个组合,无其他使用方式,还有就是,必须在V2版本,也就是@ComponentV2装饰的自定义组件中,否则会报异常。 以下和其他装饰器结合使用就是错误的案例: @Local @Once testContent: string = "Hello World" 会报错异常: '@Once' works only when used with '@Param' in pairs. 异常截图如下:

前言
本文代码案例基于Api13。
最近准备把refresh刷新库的装饰器由V1升级至V2时,遇到了一个问题,在@Prop装饰器切换@Param装饰器时,发现了自定义组件的属性无法修改问题,提示报错:
Cannot assign to 'testContent' because it is a read-only property. <ArkTSCheck>
实际错误截图:
错误原因为,@param装饰的变量仅支持本地初始化,不允许在组件内部直接修改变量本身。
虽然知道了原因,但是由于V1版本的逻辑,在自定义组件中除了来自于调用者的传递之外,而自身的属性也需要进行动态修改,否则改动量就很大,正要寻找他法进行实现时,@Once装饰器映入了眼帘。
什么是@Once装饰器
@Once装饰器作为辅助装饰器,本身没有对装饰类型的要求以及对变量的观察能力,但是它具有有两个作用,第一个是解决@Param装饰器修饰后的属性不能修改问题,第二个就是,实现仅从外部初始化一次、不接受后续同步变化的能力,也就是当后续数据源更改时,不会将修改同步给子组件。
有一点需要注意,那就是@Once装饰器不能单独使用,必须 搭配@Param使用,结合使用时,不会影响@Param的观测能力,仅针对数据源的变化做拦截,还有就是谁在前谁在后,这个都不会造成影响。
搭配使用时,前后位置都可以:
@Param @Once testContent: string = "测试数据一"
@Once @Param testContent2: string = "测试数据一"
使用场景
如果我们仅用 @param装饰进行修饰,会发现,调用者只要数据有改变就会引起自定义组件数据变化,如果你想仅仅初始化进来数据同步一下,之后数据变化无须在同步,那么就可以使用@Once装饰器进行修饰,修饰后,无论怎么修改都不会引起数据变化。
@ComponentV2
struct RefreshLayout {
@Param @Once testContent: string = "测试数据一"
build() {
Column() {
Text(this.testContent)
}
}
}
@Entry
@ComponentV2
struct Index {
@Local testContent: string = "Hello World"
build() {
Column() {
RefreshLayout({ testContent: this.testContent })
Button("点击改变")
.margin({ top: 20 })
.onClick(() => {
this.testContent = "测试数据二"
})
}.width("100%")
.height("100%")
.justifyContent(FlexAlign.Center)
}
}
上面的情况是外部调用者进行更新,不想引起自定义组件发生数据改变,如果你想在自定义组件内部,使用@Param修饰后的属性,可以发生改变,且能更新UI,那么就可以使用@Once装饰器进行修饰。
@ComponentV2
struct RefreshLayout {
@Param @Once testContent: string = "测试数据一"
build() {
Column() {
Text(this.testContent)
Button("点击改变")
.margin({ top: 20 })
.onClick(() => {
this.testContent = "测试数据二"
})
}
}
}
@Entry
@ComponentV2
struct Index {
@Local testContent: string = "Hello World"
build() {
Column() {
RefreshLayout({ testContent: this.testContent })
}.width("100%")
.height("100%")
.justifyContent(FlexAlign.Center)
}
}
相关总结
@Once装饰器只能与@Param搭配使用,仅此一个组合,无其他使用方式,还有就是,必须在V2版本,也就是@ComponentV2装饰的自定义组件中,否则会报异常。
以下和其他装饰器结合使用就是错误的案例:
@Local @Once testContent: string = "Hello World"
会报错异常:
'@Once' works only when used with '@Param' in pairs. <ArkTSCheck>
异常截图如下: