##鸿蒙开发能力 ##HarmonyOS SDK 应用服务 ##鸿蒙金融类应用 (金融理财 #
前言
之前就 Observed 和 ObjectLink 写过一篇讲解博客【HarmonyOS】 多层嵌套对象通过@ObjectLink和@Observed实现渲染更新处理!
其中就 @Observe 监听类的使用,@ObjectLink 进行数据传递进行了讲解。但是其中有些细节没有展开讲,对使用可能会有误解,所以新增一篇详细讲述。
特性明确
对于 @ObjectLink 和 @Observed,我们一般理解为对嵌套对象进行属性监听的一组状态管理标签。该组标签的诞生是为了解决嵌套对象 or 数组套数组,数组套对象等等,这种类似数据结构的监听问题,以便于 ArkUI 框架监听,来实现数据变化,UI 渲染。
但是我们使用时,需要明确其作用范围,这样就可以避免一些奇怪的 bug。
使用 @ObjectLink 和 @Observed 只能监听嵌套后的一级对象属性以及基类属性,无法监听子级及其以下的对象属性。
该结论以我上一篇博客举例,可以点击跳转到该博客,将 DEMO 示例代码 copy 下来,边看讲解,边操作 DEMO 效果更容易理解。
在列表操作数据变化时,我们即操作了一级属性,也操作了二级和三级属性,进行了数值修改。
if 判断包裹的 select 属性为 @ObjuectLink 直接监听的对象一级属性,如果我们操作了该属性数值变化,就会导致 UI 刷新。所以 if 语句块下方的 index 和 content 内容变化也能刷新到 UI。
该效果可参见前三个 Item,点击后就无效果。只有后三个点击后才会有 UI 刷新。
如此情况如何解决呢?其实嵌套深层次数据结构监听问题,已反馈给华为官方。他们还在开发中,目前 V2 接口已经可实现嵌套深层次的监听问题。
@ObservedV2 装饰器和 @Trace 装饰器:类属性变化观测,但是新的状态管理标签,还未开发完成,目前不推荐使用,因为不是最终版,随时会变化。
目前该问题的解决方案是:
1.进行二次拆分,继续往下监听对象,这样就可以实现多层数据监听。
但是如果嵌套层数过多,每一层都这样拆分,太过去繁琐。所以我推荐第二种方式,即:
2.对监听层的属性对象,进行操作赋值,不对属性对象之下的属性进行单独赋值。
以我上一篇 demo 示例代码举例:
当然了,还有一种最简单的方式就是,每次你改变嵌套数据时,监听层有属性也会变化,那 UI 就会及时刷新。如我 DEMO 示例一样,正常情况下,我们的 Select 属性是一定会改变,那 UI 就会及时刷新。
DEMO 示例
以下 DEMO 示例验证过程【使用 @ObjectLink 和 @Observed 只能监听嵌套后的一级对象属性以及基类属性,无法监听子级及其以下的对象属性】
import { ButtonModifier, TextModifier } from '@ohos.arkui.modifier';
let NextID: number = 1;
@Observedclass Bag { public id: number; public size: number;
constructor(size: number) { this.id = NextID++; this.size = size; }}
@Observedclass BagCopy { public id: number; public size: number;
constructor(size: number) { this.id = NextID++; this.size = size; }}
@Observedclass Cup { public id: number; public size: number;
constructor(size: number) { this.id = NextID++; this.size = size; }}
@Observedclass User { public bag: Bag;
constructor(bag: Bag) { this.bag = bag; }}
@Observedclass Book { public bookName: BookName;
constructor(bookName: BookName) { this.bookName = bookName; }}
@Observedclass BookName extends BagCopy { public nameSize: number; public cup: Cup;
constructor(nameSize: number) { // 调用父类方法对nameSize进行处理 super(nameSize); this.nameSize = nameSize; this.cup = new Cup(nameSize); }}
@Componentstruct ViewA { label: string = 'ViewA'; @ObjectLink bag: Bag;
private mTextCommonStyle = new TextCommonStyle(); private mButtonCommonStyle = new ButtonCommonStyle();
build() { Column() { Text(`ViewA`) .attributeModifier(this.mTextCommonStyle)
Text(`this.bag.size = ${this.bag.size}`) .attributeModifier(this.mTextCommonStyle)
Button(`click this.bag.size add 1`) .attributeModifier(this.mButtonCommonStyle) .onClick(() => { this.bag.size += 1; }) } .backgroundColor(Color.Blue) }}
@Componentstruct ViewC { label: string = 'ViewC1'; @ObjectLink bookName: BookName;
private mTextCommonStyle = new TextCommonStyle(); private mButtonCommonStyle = new ButtonCommonStyle();
build() { Row() { Column() { Text(`ViewC`) .attributeModifier(this.mTextCommonStyle)
Text(`this.bookName.cup.size = ${this.bookName.cup.size}`) .attributeModifier(this.mTextCommonStyle)
Button(`click this.bookName.cup.size add 1`) .attributeModifier(this.mButtonCommonStyle) .onClick(() => { // 当前监听对象的属性,如果是嵌套对象,则该嵌套对象的属性赋值,不会被框架监听到,UI不刷新 this.bookName.cup.size += 1; console.log('this.bookName.size:' + this.bookName.size) })
Divider().height(5)
Text(`this.bookName.size = ${this.bookName.size}`) .attributeModifier(this.mTextCommonStyle)
Button(`click this.bookName.size add 1`) .attributeModifier(this.mButtonCommonStyle) .onClick(() => { // 当前监听对象的基类属性被修改,依旧可以被监听到,UI会刷新 this.bookName.size += 1; console.log('this.bookName.size:' + this.bookName.size) })
} .width(320) .backgroundColor(Color.Red) } }}
class TextCommonStyle implements AttributeModifier<TextModifier> { applyNormalAttribute(instance: TextModifier): void { instance .fontColor('#ffffffff') .backgroundColor('#ff3d9dba') .width(320) .height(50) .borderRadius(25) .margin(10) .textAlign(TextAlign.Center) }}
class ButtonCommonStyle implements AttributeModifier<ButtonModifier> { applyNormalAttribute(instance: ButtonModifier): void { instance .width(320) .backgroundColor('#ff17a98d') .margin(10) }}
@Entry@Component@Previewstruct ViewB { @State user: User = new User(new Bag(0)); @State child: Book = new Book(new BookName(0));
build() { Scroll(){ Column() { ViewA({ bag: this.user.bag }) .width(320) ViewC({ bookName: this.child.bookName }) .width(320) Button(`ViewB: this.child.bookName.size add 10`) .width(320) .backgroundColor('#ff17a98d') .margin(10) .onClick(() => { this.child.bookName.size += 10 console.log('this.child.bookName.size:' + this.child.bookName.size) }) Button(`ViewB: this.user.bag = new Bag(10)`) .width(320) .backgroundColor('#ff17a98d') .margin(10) .onClick(() => { this.user.bag = new Bag(10); }) Button(`ViewB: this.user = new User(new Bag(20))`) .width(320) .backgroundColor('#ff17a98d') .margin(10) .onClick(() => { this.user = new User(new Bag(20)); }) } } }}
复制代码
评论