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

鸿蒙HarmonyOS开发:@Observed装饰器和@ObjectLink装饰器:嵌套类对象属性变化

文章目录

      • 一、装饰器
      • 二、概述
      • 三、限制条件
      • 四、装饰器说明
      • 五、Toggle组件
        • 1、子组件
        • 2、接口
        • 3、ToggleType枚举
        • 4、事件
      • 六、示例演示
        • 1、代码
        • 2、效果

一、装饰器

  • @State装饰器:组件内状态
  • @Prop装饰器:父子单向同步
  • @Link装饰器:父子双向同步
  • @Provide装饰器和@Consume装饰器:与后代组件双向同步

上文所述的装饰器仅能观察到第一层的变化,但是在实际应用开发中,应用会根据开发需要,封装自己的数据模型。对于多层嵌套的情况,比如二维数组,或者数组项class,或者class的属性是class,他们的第二层的属性变化是无法观察到的。这就引出了@Observed/@ObjectLink装饰器。

二、概述

@ObjectLink和@Observed类装饰器用于在涉及嵌套对象或数组的场景中进行双向数据同步:

被@Observed装饰的类,可以被观察到属性的变化;

子组件中@ObjectLink装饰器装饰的状态变量用于接收@Observed装饰的类的实例,和父组件中对应的状态变量建立双向数据绑定。这个实例可以是数组中的被@Observed装饰的项,或者是class object中的属性,这个属性同样也需要被@Observed装饰。

@Observed用于嵌套类场景中,观察对象类属性变化,要配合自定义组件使用,如果要做数据双/单向同步,需要搭配@ObjectLink或者@Prop使用。

三、限制条件

使用@Observed装饰class会改变class原始的原型链,@Observed和其他类装饰器装饰同一个class可能会带来问题。

@ObjectLink装饰器不能在@Entry装饰的自定义组件中使用。

四、装饰器说明

@Observed类装饰说明
装饰器参
类装饰器装饰class。需要放在class的定义前,使用new创建类对象。
@ObjectLink变量装饰器说明
装饰器参数
允许装饰的变量类型必须为被@Observed装饰的class实例,必须指定类型。
不支持简单类型,可以使用@Prop。
支持继承Date、Array的class实例,API11及以上支持继承Map、Set的class实例。
@ObjectLink的属性是可以改变的,但是变量的分配是不允许的,也就是说这个装饰器装饰变量是只读的,不能被改变。
被装饰变量的初始值不允许。

五、Toggle组件

组件提供勾选框样式、状态按钮样式及开关样式。

1、子组件

仅当ToggleType为Button时可包含子组件。

2、接口

Toggle(options: { type: ToggleType, isOn?: boolean })

  • 参数
参数名参数类型必填参数描述
typeToggleType开关的样式。
默认值:ToggleType.Switch。
isOnboolean开关是否打开,true:打开,false:关闭。
默认值:false
从API version 10开始,该参数支持$$双向绑定变量。
3、ToggleType枚举
名称描述
Checkbox提供单选框样式。
Button提供状态按钮样式,如果子组件有文本设置,则相应的文本内容会显示在按钮内部。
默认尺寸为:高为28vp,宽无默认值。
Switch提供开关样式。

在这里插入图片描述

4、事件

开关状态切换时触发该事件。

onChange(callback: (isOn: boolean) => void)

  • 参数
参数名类型必填说明
isOnboolean为true时,代表状态从关切换为开。false时,代表状态从开切换为关。

六、示例演示

本示例演示联系人管理功能页面。
可以新增,删除,收藏,展开手机号登功能。
使用到的组件间相互通信功能
@Prop装饰器:父子单向同步
@Link装饰器:父子双向同步
@Watch装饰器监听状态变量的变化
@Observed装饰器和@ObjectLink装饰器:嵌套类对象属性变化
@Extend装饰器:定义扩展组件样式
Toggle组件

1、代码
// 定义变量ID,默认从1开始,自增
let id = 1// @Observed装饰的类
@Observed
class Person {name: stringphone: stringisCollect: boolean = falseid: numberconstructor(name: string, phone: string) {// id自增this.id = id++this.name = namethis.phone = phone}
}// 随机姓名方法,为了演示简写
function getRandomName() {return "张三" + Math.floor(Math.random() * 100)
}//随机手机号,为了演示简写
function getRandomPhone() {return "1" + (Math.floor(Math.random() * 9000000000) + 1000000000)
}@Entry
@Component
struct ContactsList {// 联系人列表@State contactsList: Person[] = [new Person(getRandomName(), getRandomPhone()), new Person(getRandomName(), getRandomPhone())]// 当前展开的联系人ID@State currentExpandID: number = 0// 是否点击选中@State isSelect: boolean = false// 选中的联系人ID列表@State selectIdList: number[] = []build() {Column() {Row({ space: 10 }) {Text("联系人管理").fontSize(20)Blank()Button(this.isSelect ? "取消" : "选中")// 扩展组件样式.globalButtonStyle(Color.Gray)// 点击切换选中/取消按钮事件.onClick(() => {this.isSelect = !this.isSelectthis.selectIdList = []})Button("+")// 扩展组件样式.globalButtonStyle(Color.Gray).onClick(() => {// 新增联系人this.contactsList.push(new Person(getRandomName(), getRandomPhone()))})}.width("100%").padding(10)List({ space: 10 }) {ForEach(this.contactsList, (item: Person) => {ListItem() {// 观察对象类属性变化,要配合自定义组件使用ContactsItem({ item,currentExpandID: $currentExpandID,isSelect: this.isSelect,selectIdList: $selectIdList })}})}.padding(10).layoutWeight(1)if (this.isSelect) {Button("删除").margin(10)// 扩展组件样式.globalButtonStyle(Color.Red)// 删除按钮点击事件.onClick(() => {this.contactsList = this.contactsList.filter((item: Person) => {return !this.selectIdList.includes(item.id)})})}}.width('100%').height('100%').backgroundColor("#f7f7f7")}
}// 自定义组件
@Component
struct ContactsItem {// 数据双向同步,需要搭配@ObjectLink@ObjectLink item: Person// 组件内状态@State isExpand: boolean = false// 父子双向同步 监听状态变化@Link @Watch("onChangeCurrentID") currentExpandID: number// 父子单向同步@Prop isSelect: boolean// 父子双向同步@Link selectIdList: number[]// 监听状态变量变化回调onChangeCurrentID() {if (this.item.id != this.currentExpandID) {this.isExpand = false}}build() {Column() {Row({ space: 10 }) {// 复选框if (this.isSelect) {Toggle({ type: ToggleType.Checkbox })// 选中状态发生变化时的事件.onChange((val) => {if (val) {this.selectIdList.push(this.item.id)} else {let index: number = this.selectIdList.indexOf(this.item.id)this.selectIdList.splice(index, 1)}})}// 头像Image($r("app.media.picture")).width(30).height(30)// 姓名Text(this.item.name).fontSize(18)Blank()// 收藏Image(this.item.isCollect ? $r("app.media.collect_select") : $r("app.media.collect")).width(26).height(26).onClick(() => {// 第二层的属性值变化this.item.isCollect = !this.item.isCollect})}.height(40).width("100%")// 手机号if (this.isExpand) {Divider().margin({ top: 10, bottom: 6 }).color("#EEEEEE")Row() {Text("手机号码:" + this.item.phone).fontSize(16)}.height(30).width("100%")}}.width("100%").padding(10).borderRadius(6).backgroundColor(Color.White)// 点击展开显示手机号码.onClick(() => {this.isExpand = !this.isExpandthis.currentExpandID = this.item.id})}
}// 定义扩展组件样式
@Extend(Button) function globalButtonStyle(color: Color) {.height(30).fontSize(14).backgroundColor(color)
}
2、效果
  • 点击新增按钮,可以新增联系人
  • 点击收藏按钮,可以切换是否收藏
    在这里插入图片描述
  • 点击联系人,可以展开当前联系人,查看手机号码
  • 点击上面选择按钮,可以切换选择页面
  • 点击联系人前面复选框,可以选中联系
  • 点击删除按钮,可以删除选中的联系人
    在这里插入图片描述

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 在Python中创建和操作字典的全面指南
  • 【云原生】Helm来管理Kubernetes集群的详细使用方法与综合应用实战
  • 《看漫画学Python》全彩PDF教程,495页深度解析,零基础也能轻松上手!
  • Java中的SSL/TLS安全通信实现
  • 职场里有3个错觉,如果正好说中你,抓紧醒过来
  • 数据同步策略概览
  • 计算机网络-IGMP Snooping特性
  • python 参数输入
  • 【黄啊码】Gradio配合Openai接口实现机器人问答对话
  • JAR文件中混淆和加密class文件
  • Linux系统编程-多路IO套接字
  • GenAI 会消灭软件开发人员的工作吗?
  • Modbus通讯协议
  • linux top
  • 蓝牙网关北京厂家_蓝牙网关型号价格介绍
  • 【个人向】《HTTP图解》阅后小结
  • 【刷算法】从上往下打印二叉树
  • Angular6错误 Service: No provider for Renderer2
  • CSS相对定位
  • IndexedDB
  • JAVA之继承和多态
  • JWT究竟是什么呢?
  • mongo索引构建
  • python大佬养成计划----difflib模块
  • React as a UI Runtime(五、列表)
  • vuex 学习笔记 01
  • 动手做个聊天室,前端工程师百无聊赖的人生
  • 排序算法学习笔记
  • 双管齐下,VMware的容器新战略
  • 一起来学SpringBoot | 第十篇:使用Spring Cache集成Redis
  • 智能网联汽车信息安全
  • mysql面试题分组并合并列
  • ​520就是要宠粉,你的心头书我买单
  • #NOIP 2014# day.1 T2 联合权值
  • #QT(智能家居界面-界面切换)
  • #微信小程序:微信小程序常见的配置传旨
  • ${factoryList }后面有空格不影响
  • (1)bark-ml
  • (55)MOS管专题--->(10)MOS管的封装
  • (解决办法)ASP.NET导出Excel,打开时提示“您尝试打开文件'XXX.xls'的格式与文件扩展名指定文件不一致
  • (亲测有效)推荐2024最新的免费漫画软件app,无广告,聚合全网资源!
  • (四)Android布局类型(线性布局LinearLayout)
  • (转)eclipse内存溢出设置 -Xms212m -Xmx804m -XX:PermSize=250M -XX:MaxPermSize=356m
  • (轉貼) 資訊相關科系畢業的學生,未來會是什麼樣子?(Misc)
  • ***微信公众号支付+微信H5支付+微信扫码支付+小程序支付+APP微信支付解决方案总结...
  • .NET 5.0正式发布,有什么功能特性(翻译)
  • .NET 8 编写 LiteDB vs SQLite 数据库 CRUD 接口性能测试(准备篇)
  • .net framework profiles /.net framework 配置
  • .NET 程序如何获取图片的宽高(框架自带多种方法的不同性能)
  • .net 使用$.ajax实现从前台调用后台方法(包含静态方法和非静态方法调用)
  • .NET/C# 编译期间能确定的相同字符串,在运行期间是相同的实例
  • .Net插件开发开源框架
  • //解决validator验证插件多个name相同只验证第一的问题
  • @JoinTable会自动删除关联表的数据
  • @media screen 针对不同移动设备