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

news2024/9/22 4:35:27

文章目录

      • 一、装饰器
      • 二、概述
      • 三、限制条件
      • 四、装饰器说明
      • 五、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: string
  phone: string
  isCollect: boolean = false
  id: number

  constructor(name: string, phone: string) {
    // id自增
    this.id = id++
    this.name = name
    this.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.isSelect
            this.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.isExpand
      this.currentExpandID = this.item.id
    })
  }
}

// 定义扩展组件样式
@Extend(Button) function globalButtonStyle(color: Color) {
  .height(30)
  .fontSize(14)
  .backgroundColor(color)
}
2、效果
  • 点击新增按钮,可以新增联系人
  • 点击收藏按钮,可以切换是否收藏
    在这里插入图片描述
  • 点击联系人,可以展开当前联系人,查看手机号码
  • 点击上面选择按钮,可以切换选择页面
  • 点击联系人前面复选框,可以选中联系
  • 点击删除按钮,可以删除选中的联系人
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1994281.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux云计算 |【第二阶段】NETWORK-DAY1

主要内容: 计算机网络概述、网络拓扑结构、OSI参考模型、eNSP、交换机及原理 一、计算机网络概述 计算机网络是指将多台计算机或设备通过通信线路连接起来,以便它们能够相互交换信息和共享资源的系统。计算机网络的目的是实现数据通信和资源共享&#…

生成式人工智能安全评估体系构建

文章目录 前言一、人工智能安全治理的现状1.1 国际安全治理现状1.2 国内安全治理现状二、构建人工智能安全评估体系1.1 需要对生成式人工智能技术的安全性、可靠性、可控性、公平性等维度进行全面的考量。1.2 应对生成式人工智能全维度风险。1.3 在体系化应对框架中,应明确法律…

[Meachines] [Easy] Traverxec Nostromo RCE+SSH-私钥RSA解密+journalctl权限提升

信息收集 IP AddressOpening Ports10.10.10.165TCP:22,80 $ nmap -p- 10.10.10.165 --min-rate 1000 -sC -sV PORT STATE SERVICE VERSION …

nfc苹果手机怎么开启?3招就教会你

在数字化时代,nfc技术已成为智能手机的一项重要功能,它让我们的设备能够进行无线数据交换,实现便捷的移动支付、文件传输等操作。那么,nfc苹果手机怎么开启呢?如果你想要充分利用这一技术,那么本文将为你提…

git推送错误-->远程分支比本地的分支更新,无法直接推送

每次上传本地修改好的代码的时候,十次有八次都会出现这样的问题!!(暴躁!!!) 现在写个帖子记录一下,这个问题目前我还没有解决,欢迎懂的佬指点一下. 情景: 我在本地仓库做了一些代码的修改,准备上传到远程仓库上,下边是上传步骤: git add . # 将所有的修改都提交到缓冲区git …

免费获取!Windows10 32位纯净版:无捆绑更安全!

今日,系统之家小编给大家分享2024最新的Windows10纯净版32位系统,该版本系统不包含任何捆绑软件,系统资源占用少,运作流畅,适合老旧电脑安装。系统安装起来特别简单,推荐大家使用硬盘安装,即便是…

大黄蜂能飞的起来吗?

Bumblebee argument 虽然早期的空气动力学证明大黄蜂不能飞行——因为体重太重,翅膀太薄,但大黄蜂并不知道,所以照飞不误。 背景 在20世纪初,‌科学家们通过研究发现,‌大黄蜂的身体与翼展的比例失调,‌按照…

OpenAI Embedding效果表现不佳:那如何评估选择Embedding?

OpenAI Embedding效果表现不佳 对文本进行Embedding是大模型应用中必不可少的一步, 虽然大模型OpenAI是最好的, 但OpenAI的Embedding却不是。本文Embedding评估的具体流程, 代码, 以及结论。 如果仅关心代码 & 结论&#xf…

软件项目质量管理体系,软件评审,资质认证,安全建设及项目管理匹配资料(原件参考)

软件项目质量管理体系是指一套系统化的管理方法、流程、工具和文档,旨在确保软件项目从需求分析、设计、开发、测试到部署和维护的整个生命周期中,都能达到预定的质量标准和客户期望。该体系通过明确的角色和责任、标准化的工作流程、有效的质量控制和持…

NC 找到搜索二叉树中两个错误的节点

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 描述 一棵二叉树原…

Windows系统下的MATLAB 虚拟机中Ubuntu系统的ROS通讯

在Windows系统下的MATLAB与虚拟机中Ubuntu系统的ROS进行通讯,主要涉及到网络配置、环境变量设置以及MATLAB与ROS的接口调用。以下是一个详细的步骤说明: 一、网络配置 设置虚拟机网络: 确保虚拟机(Ubuntu系统)的网络…

7-3 单机多卡并行

一台机器可以安装多个GPU(1-16)在训练和预测时,我们将一个小批量计算切分到多个GPU上来达到加速的目的 同样一个小批量,让用多个GPU同时运行来一起完成这个计算梯度的过程常用的切分方案有 数据并行 模型并行 通道并行&#xff…

中国中医科学院某医院:监控易7.0开启一体化运维新篇章

在首都北京的医疗领域中,中国中医科学院某医院作为佼佼者,一直致力于为患者提供高质量的医疗服务。然而,随着医院业务的不断扩展和IT系统的日益复杂,如何确保IT基础资源的稳定运行,成为了医院面临的一大挑战。为了应对…

Java继承细节

目录 继承给编程带来的便利 细节1 案例演示 细节2 案例演示 细节3 案例演示 细节4 案例演示 细节5 细节6 细节7 案例演示 细节8 细节9 细节10 继承给编程带来的便利 提高了代码的复用性,代码的扩展性与维护性。 细节1 子类继承了所有的属性和方法…

Java面试题--JVM大厂篇之破解 JVM 性能瓶颈:实战优化策略大全

目录 引言: 正文: 1. 常见的JVM性能问题 频繁的GC导致应用暂停 内存泄漏导致的内存不足 线程争用导致的CPU利用率过高 类加载问题导致的启动时间过长 2. 优化策略大全 2.1 代码层面的优化 2.1.1 避免不必要的对象创建 2.1.2 优化数据结构的选择 2.1.3 使用并发工具…

【文心超级智能体创造营】打造「潮流穿搭助手」智能体 引领潮流新动向

【文心超级智能体创造营】打造潮流穿搭助手 引领潮流新动向 文章目录 【文心超级智能体创造营】打造潮流穿搭助手 引领潮流新动向一、智能体发展背景二、文心智能体平台—AgentBuilder一图概览三、我的智能体—潮流穿搭助手3.1 智能体初步设想3.2 prompt提示词准备3.3 &#x1…

LabVIEW中CANopen 读取程序解读

这段程序用于创建 CANopen 接口,并读取 CANopen CAN 帧消息。以下是详细的解读: 左侧部分 node-ID (U8): 指定节点 ID,用于标识 CANopen 网络中的设备。CANopen interface (U32): 指定 CANopen 接口。baud rate (U32): 设置波特率&#xff0…

企业如何发布新闻稿到全球媒体上?

在经济全球化的今天,中国某个小县生产的商品可能会卖到全国各地,我们国家很多本土品牌面临出海的难题。当然有些企业已经通过国外的代理商把货品铺到了国外的市场,有的通过亚马逊这样的电商平台进行销售,但这些只是铺货&#xff0…

基于融合正余弦和柯西变异的麻雀搜索算法SCSSA优化CNN-BiLSTM的多变量时间序列预测

matlab R2024a以上 一、数据集 二、融合正余弦和柯西变异的麻雀搜索算法 麻雀搜索算法(Sparrow Search Algorithm, SSA)是一种新型的群体智能优化算法,其灵感来源于麻雀觅食行为。为了提高算法的性能,可以融合正余弦函数和柯西变…

基于SpringBoot+Vue的城市垃圾分类管理系统(带1w+文档)

基于SpringBootVue的城市垃圾分类管理系统(带1w文档) 基于SpringBootVue的城市垃圾分类管理系统(带1w文档) 信息数据的处理完全依赖人工进行操作,会耗费大量的人工成本,特别是面对大量的数据信息时,传统人工操作不仅不能对数据的出错率进行保…