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

【HarmonyOS】深入理解@Observed装饰器和@ObjectLink装饰器:嵌套类对象属性变化

【HarmonyOS】深入理解@Observed装饰器和@ObjectLink装饰器:嵌套类对象属性变化

前言

之前就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;
class Bag {public id: number;public size: number;constructor(size: number) {this.id = NextID++;this.size = size;}
}
class BagCopy {public id: number;public size: number;constructor(size: number) {this.id = NextID++;this.size = size;}
}
class Cup {public id: number;public size: number;constructor(size: number) {this.id = NextID++;this.size = size;}
}
class User {public bag: Bag;constructor(bag: Bag) {this.bag = bag;}
}
class Book {public bookName: BookName;constructor(bookName: BookName) {this.bookName = bookName;}
}
class BookName extends BagCopy {public nameSize: number;public cup: Cup;constructor(nameSize: number) {// 调用父类方法对nameSize进行处理super(nameSize);this.nameSize = nameSize;this.cup = new Cup(nameSize);}
}
struct ViewA {label: string = 'ViewA'; 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)}
}
struct ViewC {label: string = 'ViewC1'; 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)}
}


struct ViewB { user: User = new User(new Bag(0)); 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 += 10console.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));})}}}
}

相关文章:

  • 403高效绕过目录扫描工具
  • 《C++魔法:零开销实现抽象工厂模式》
  • ES数据的删除与备份
  • 2024年研究生数学建模“华为杯”E题——肘部法则、k-means聚类、目标检测(python)、ARIMA、逻辑回归、混淆矩阵(附:目标检测代码)
  • 微服务注册中⼼1
  • springboot实战学习(7)(JWT令牌的组成、JWT令牌的使用与验证)
  • Playerprefer类中的方法
  • 【Kubernetes】日志平台EFK+Logstash+Kafka【实战】
  • Vue引入js脚本问题记录(附解决办法)
  • 数据库 - MySQL数据查询
  • ❤Node11-登录人token信息接口
  • 页面禁用鼠标右键属于反爬虫措施吗 ?
  • Python--操作列表
  • 《柔性供料器原理及用途》JKTECH柔性振动盘
  • 设计模式实战——开发中常用到的单例模式
  • 【翻译】Mashape是如何管理15000个API和微服务的(三)
  • 2018以太坊智能合约编程语言solidity的最佳IDEs
  • classpath对获取配置文件的影响
  • Git学习与使用心得(1)—— 初始化
  • JDK 6和JDK 7中的substring()方法
  • Python爬虫--- 1.3 BS4库的解析器
  • Shadow DOM 内部构造及如何构建独立组件
  • Spring Boot快速入门(一):Hello Spring Boot
  • VuePress 静态网站生成
  • Web Storage相关
  • 从@property说起(二)当我们写下@property (nonatomic, weak) id obj时,我们究竟写了什么...
  • 搭建gitbook 和 访问权限认证
  • 关于extract.autodesk.io的一些说明
  • 聚类分析——Kmeans
  • 开源中国专访:Chameleon原理首发,其它跨多端统一框架都是假的?
  • 浅谈Golang中select的用法
  • 推荐一个React的管理后台框架
  • 小试R空间处理新库sf
  • 正则与JS中的正则
  • ​DB-Engines 11月数据库排名:PostgreSQL坐稳同期涨幅榜冠军宝座
  • ###项目技术发展史
  • $(selector).each()和$.each()的区别
  • $redis-setphp_redis Set命令,php操作Redis Set函数介绍
  • (10)工业界推荐系统-小红书推荐场景及内部实践【排序模型的特征】
  • (delphi11最新学习资料) Object Pascal 学习笔记---第14章泛型第2节(泛型类的类构造函数)
  • (八)Spring源码解析:Spring MVC
  • (计算机网络)物理层
  • (蓝桥杯每日一题)平方末尾及补充(常用的字符串函数功能)
  • (亲测成功)在centos7.5上安装kvm,通过VNC远程连接并创建多台ubuntu虚拟机(ubuntu server版本)...
  • (十五)Flask覆写wsgi_app函数实现自定义中间件
  • (四)事件系统
  • (一)spring cloud微服务分布式云架构 - Spring Cloud简介
  • (转)JAVA中的堆栈
  • .Net 高效开发之不可错过的实用工具
  • .NET/C# 编译期能确定的字符串会在字符串暂存池中不会被 GC 垃圾回收掉
  • .net6解除文件上传限制。Multipart body length limit 16384 exceeded
  • .NET开源全面方便的第三方登录组件集合 - MrHuo.OAuth
  • .pub是什么文件_Rust 模块和文件 - 「译」
  • @GetMapping和@RequestMapping的区别
  • @RequestMapping 的作用是什么?