管理组件状态

概述

在应用中,界面通常都是动态的。如图1所示,在子目标列表中,当用户点击目标一,目标一会呈现展开状态,再次点击目标一,目标一呈现收起状态。界面会根据不同的状态展示不一样的效果。

图1 展开/收起目标项
img

ArkUI作为一种声明式UI,具有状态驱动UI更新的特点。当用户进行界面交互或有外部事件引起状态改变时,状态的变化会触发组件自动更新。所以在ArkUI中,我们只需要通过一个变量来记录状态。当改变状态的时候,ArkUI就会自动更新界面中受影响的部分。

点击放大

ArkUI框架提供了多种管理状态的装饰器来修饰变量,使用这些装饰器修饰的变量即称为状态变量。

在组件范围传递的状态管理常见的场景如下:

场景装饰器
组件内的状态管理@State
从父组件单向同步状态@Prop
与父组件双向同步状态@Link
跨组件层级双向同步状态@Provide和@Consume

在组件内使用@State装饰器来修饰变量,可以使组件根据不同的状态来呈现不同的效果。若当前组件的状态需要通过其父组件传递而来,此时需要使用@Prop装饰器;若是父子组件状态需要相互绑定进行双向同步,则需要使用@Link装饰器。使用@Provide和@Consume装饰器可以实现跨组件层级双向同步状态。

在实际应用开发中,应用会根据需要封装数据模型。如果需要观察嵌套类对象属性变化,需要使用@Observed和@ObjectLink装饰器,因为上述表格中的装饰器只能观察到对象的第一层属性变化。@Observed和@ObjectLink装饰器的具体使用方法可参考@Observed装饰器和@ObjectLink装饰器:嵌套类对象属性变化。

另外,当状态改变,需要对状态变化进行监听做一些相应的操作时,可以使用@Watch装饰器来修饰状态。

组件内的状态管理:@State

实际开发中由于交互,组件的内容呈现可能产生变化。当需要在组件内使用状态来控制UI的不同呈现方式时,可以使用@State装饰器。以任务管理应用为例,当点击子目标列表的其中一项,列表项会展开。当再次点击同一项,列表项会收起。所以,对于某一个列表项来说,它的呈现方式会受列表项是否展开这个状态影响。

图2 展开/收起目标项
img

将是否展开这个状态定义为isExpanded变量,当其值为false表示目标项收起,值为true时表示目标项展开。

此时,需要使用@State装饰器修饰isExpanded,使其成为目标项内部的状态变量。通过@State装饰后,框架内部会建立数据与视图间的绑定,

当isExpanded状态变化时,目标项会随之展开或收起。

图3 定义是否展开状态
点击放大

其具体实现只要用@State修饰isExpanded变量,定义是否展开状态。然后通过条件渲染,实现是否显示进度调整面板和列表项的高度变化。最后,监听列表项的点击事件,在onClick回调中改变isExpanded状态。

这样就实现了对相同列表项点击时,列表项的展开和收起功能。当用户反复点击同一个列表项时,组件内的isExpanded状态变化,列表项会自动更新。

@Component
export default struct TargetListItem {@State isExpanded: boolean = false;...build() {...Column() {...if (this.isExpanded) {Blank()ProgressEditPanel(...)}}.height(this.isExpanded ? $r('app.float.expanded_item_height')                  : $r('app.float.list_item_height')).onClick(() => {...this.isExpanded = !this.isExpanded;...})...}
}

从父组件单向同步状态:@Prop

当子组件中的状态依赖从父组件传递而来时,需要使用@Prop装饰器,@Prop修饰的变量可以和其父组件中的状态建立单向同步关系。当父组件中状态变化时,该状态值也会更新至@Prop修饰的变量;对@Prop修饰的变量的修改不会影响其父组件中的状态。

图4 列表的编辑模式
img

如图4所示,在目标管理应用中,当用户点击子目标列表的“编辑”文本,列表进入编辑模式,点击取消,列表退出编辑模式。

整个列表是自定义组件TargetList,顶部是文本显示区域,主要是Text组件,底部是一个Button组件。中间区域则是用来显示每个目标项,目标项是自定义组件TargetListItem。

从图中可以看出,TargetListItem是TargetList的子组件。TargetList是TargetListItem父组件。

图5 TargetList和TargetListItem
img

对于父组件TargetList,其顶部显示的文本和底部按钮会随编辑模式的变化而变化,因此父组件拥有编辑模式状态。

对于子组件TargetListItem,其最右侧是否预留位置和显示勾选框也会随编辑模式变化,因此子组件也拥有编辑模式状态。

但是是否进入编辑模式,其触发点是在用户点击列表的“编辑”或取消按钮,状态变化的源头仅在于父组件TargetList。当父组件TargetList中的编辑模式变化时,子组件TargetListItem的编辑模式状态需要随之变化。

图6 从父组件单向同步isEditMode状态
img

在父组件TargetList中可以定义一个是否进入编辑模式的状态,即用@State修饰isEditMode。@State修饰的变量不仅是组件内部的状态,也可以作为子组件单向或双向同步的数据源。ArkUI提供了@Prop装饰器,@Prop修饰的变量可以和其父组件中的状态建立单向同步关系,所以用@Prop修饰子组件TargetListItem中的isEditMode变量。

在父组件TargetList中,用@State修饰isEditMode,定义编辑模式状态。然后利用条件渲染实现根据是否进入编辑模式,显示不同的文本和按钮。同时,在父组件中需要在用户点击时改变状态,触发界面更新。

当点击“编辑”事件发生时,进入编辑模式,显示取消、全选文本和勾选框,同时显示删除按钮;当点击“取消”事件发生时,退出编辑模式,显示“编辑”文本和“添加子目标”按钮。

@Component
export default struct TargetList {@State isEditMode: boolean = false;...build() {Column() {Row() {...if (this.isEditMode) {Text($r('app.string.cancel_button')).onClick(() => {this.isEditMode = false;...})...Text($r('app.string.select_all_button'))...Checkbox()...} else {Text($r('app.string.edit_button')).onClick(() => {this.isEditMode = true;})...}...}...List({ space: CommonConstants.LIST_SPACE }) {ForEach(this.targetData, (item: TaskItemBean, index: number) => {ListItem() {TargetListItem({isEditMode: this.isEditMode,...})}}, (item, index) => JSON.stringify(item) + index)}...if (this.isEditMode) {Button($r('app.string.delete_button'))} else {Button($r('app.string.add_task'))}}...}
}

在子组件TargetListItem中,使用@Prop修饰子组件的isEditMode变量,定义子组件的编辑模式状态。然后同样根据是否进入编辑模式,控制目标项最右侧是否预留位置和显示勾选框。

@Component
export default struct TargetListItem {@Prop isEditMode: boolean;...Column() {...}.padding({...right: this.isEditMode ? $r('app.float.list_edit_padding') : $r('app.float.list_padding')})...if (this.isEditMode) {Row() {Checkbox()...}}...
}

最后,最关键的一步就是要在父组件中使用子组件时,将父组件的编辑模式状态this.isEditMode传递给子组件的编辑模式状态isEditMode。

@Component
export default struct TargetList {@State isEditMode: boolean = false;...build() {Column() {...List({ space: CommonConstants.LIST_SPACE }) {ForEach(this.targetData, (item: TaskItemBean, index: number) => {ListItem() {TargetListItem({isEditMode: this.isEditMode,...})}}, (item, index) => JSON.stringify(item) + index)}...}...}
}

与父组件双向同步状态:@Link

若是父子组件状态需要相互绑定进行双向同步时,可以使用@Link装饰器。父组件中用于初始化子组件@Link变量的必须是在父组件中定义的状态变量。

图7 切换目标项
img

在目标管理应用中,当用户点击同一个目标,目标项会展开或者收起。当用户点击不同的目标项时,除了被点击的目标项展开,同时前一次被点击的目标项会收起。

如图7所示,当目标一展开时,点击目标三,目标三会展开,同时目标一会收起。再点击目标一时,目标一展开,同时目标三会收起。

从目标一切换到目标三的流程中,关键在于最后目标一的收起,当点击目标三时,目标一需要知道点击了目标三,目标一才会收起。

图8 子目标列表目标项位置索引
点击放大

在子目标列表中,每个列表项都有其位置索引值index属性,表示目标项在列表中的位置。index从0开始,即第一个目标项的索引值为0,第二个目标项的索引值为1,以此类推。此外,clickIndex用来记录被点击的目标项索引。当点击目标一时,clickIndex为0,点击目标三时,clickIndex为2。

在父组件子目标列表和每个子组件目标项中都拥有clickIndex状态。当目标一展开时,clickIndex为0。此时点击目标三,目标三的clickIndex变为2,只要其父组件子目标列表感知到clickIndex状态变化,同时将此变化传递给目标一。目标一的clickIndex即可同步改变为2,即目标一感知到此时点击了目标三。

图9 与父组件双向同步clickIndex状态
点击放大

将列表和目标项对应到列表组件TargetList和列表项TargetListItem。首先,需要在父组件TargetList中定义clickIndex状态。

若此时子组件中的clickIndex用@Prop装饰器修饰,当子组件中clickIndex变化时,父组件无法感知,因为@Prop装饰器建立的是从父组件到子组件的单向同步关系。

ArkUI提供了@Link装饰器,用于与父组件双向同步状态。当子组件TargetListItem中的clickIndex用@Link修饰,可与父组件TargetList中的clickIndex建立双向同步关系。

@Component
export default struct TargetList {@State clickIndex: number = CommonConstants.DEFAULT_CLICK_INDEX;...TargetListItem({clickIndex: $clickIndex,...})...
}

首先,在父组件TargetList中用@State装饰器定义点击的目标项索引状态。然后,在子组件TargetListItem中用@Link装饰器定义clickIndex,当点击目标项时,clickIndex更新为当前目标索引值。

完成在父子组件中定义状态后,最关键的就是要建立父子组件的双向关联关系。在父组件中使用子组件时,将父组件的clickIndex传递给子组件的clickIndex。其中父组件的clickIndex加上$表示传递的是引用。

@Component
export default struct TargetListItem {@Link @Watch('onClickIndexChanged') clickIndex: number;@State isExpanded: boolean = false...onClickIndexChanged() {if (this.clickIndex != this.index) {this.isExpanded = false;}}build() {...Column() {...}.onClick(() => {...this.clickIndex = this.index;...})...}
}

当目标一感知到点击了目标三时,还需要将目标一收起,切换列表项的功能才是完整的。此时,目标一感知到clickIndex变为2,需要判断与目标一本身的位置索引值0不相等,从而将目标一收起。此时,就需要用到ArkUI中监听状态变化@Watch的能力。用@Watch修饰的状态,当状态发生变化时,会触发声明时定义的回调。

我们给TargetListItem的中的clickIndex状态加上@Watch(“onClickIndexChanged”)。这表示需要监听clickIndex状态的变化。当clickIndex状态变化时,将触发onClickIndexChanged回调:如果点击的列表项索引不等于当前列表项索引,则将isExpanded状态置为false,从而收起该目标项。

跨组件层级双向同步状态:@Provide和@Consume

img

跨组件层级双向同步状态是指@Provide修饰的状态变量自动对提供者组件的所有后代组件可用,后代组件通过使用@Consume装饰的变量来获得对提供的状态变量的访问。@Provide作为数据的提供方,可以更新其子孙节点的数据,并触发页面渲染。@Consume在感知到@Provide数据的更新后,会触发当前自定义组件的重新渲染。

使用@Provide的好处是开发者不需要多次将变量在组件间传递。@Provide和@Consume的具体使用方法请参见开发指南:@Provide装饰器和@Consume装饰器:与后代组件双向同步。

参考

更多状态管理场景和相关知识请参考开发指南:状态管理。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

李沐机器学习系列1--- 线性规划

1 Introduction 1.1 线性回归函数 典型的线性回归函数 f ( x ) w ⃗ ⋅ x ⃗ f(x)\vec{w} \cdot \vec{x} f(x)w ⋅x 现实生活中,简单的线性回归问题很少,这里有一个简单的线性回归问题。房子的价格和房子的面积以及房子的年龄假设成线性关系。 p r …

2023机器人行业总结,2024机器人崛起元年(具身智能)

2023总结: 1.Chatgpt引爆了通用人工智能,最大的受益者或是机器人,2023年最热门的创业赛道便是人形机器人,优必选更是成为人形机器人上市第一股, 可以说2023年是机器人开启智能化的元年,而2024则将成为机器…

go执行静态二进制文件和执行动态库文件

目的和需求:部分go的核心文件不开源,例如验证,主程序核心逻辑等等 第一个想法,把子程序代码打包成静态文件,然后主程序执行 子程序 package mainimport ("fmt""github.com/gogf/gf/v2/os/gfile"…

[笔记] 使用 qemu 创建虚拟磁盘并安装 grub

之前使用 wsl 进行了直接创建虚拟磁盘并安装 grub,现在希望能够直接借助 qemu 的工具创建虚拟磁盘文件并安装 grub,由于需要用到 nbd(net block device网络块设备) 模块,在 wsl 中并不支持,因此这里使用到了 Hypver-V 虚拟机创建了一个 Ubuntu 系统,在系统中安装了 qemu 和 gru…

Spring Cloud Gateway + Nacos 实现动态路由

1、maven 依赖 主要依赖 <!-- 网关 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency>案件差不多完整主要依赖 <!--Spring boot 依赖(微服务基…

uni-app 前后端调用实例 基于Springboot 详情页实现

锋哥原创的uni-app视频教程&#xff1a; 2023版uniapp从入门到上天视频教程(Java后端无废话版)&#xff0c;火爆更新中..._哔哩哔哩_bilibili2023版uniapp从入门到上天视频教程(Java后端无废话版)&#xff0c;火爆更新中...共计23条视频&#xff0c;包括&#xff1a;第1讲 uni…

分布微服软件体系快速云端架构

1 概述 分布微服软件体系云端架构平台&#xff0c;以主流的NACOS服务器作为注册配置中心&#xff0c;采用主流的Gradle框架&#xff0c;内嵌Tomcat10以上版本&#xff0c;用于快速构造各类基于JDK17以上的信息应用系统的分布式微服务软件体系架构&#xff0c;可以适用关系型SQ…

k8s的网络

k8s的网络 k8s中的通信模式&#xff1a; 1、pod内部之间容器与容器之间的通信 在同一个pod中的容器共享资源和网络&#xff0c;使用同一个网络命名空间&#xff0c;可以直接通信的 2、同一个node节点之内&#xff0c;不同pod之间的通信 每个pod都有一个全局的真实的ip地址…

缓存cache和缓冲buffer的区别

目录 缓存&#xff08;cache&#xff09; 浏览器缓存 内存缓存 redis 缓冲&#xff08;buffer&#xff09; java 实现 BufferedInputStream BufferedOutputStream BufferedReader BufferedWriter 数据库中的 join buffer 总结 近期被这两个词汇困扰了&#xff0c;感…

SQL中 Group by Grouping Sets 分组的用法

文章目录 1. 用法2. 语法3. 实际应用3.1 求总和与小计3.2 按多个维度分组3.3 标记小计和总计 1. 用法 将Grouping Sets 运算符添加到Group by 子句中&#xff0c;使用Grouping Set 可以在一个查询中指定数据的多个分组&#xff0c;其结果与针对指定的组执行union all 运算等效…

玩机技巧|电脑下方的任务栏卡死如何解决

你是否遇到过&#xff0c;电脑下方的任务栏点不动&#xff0c;开始菜单点击了都没有反应的情况。你是否还在强制性关机&#xff08;按电源&#xff09;的解决这个问题。废话不多说&#xff0c;上干货 首先点击键盘上的ctrlshiftesc键&#xff0c;弹出任务管理器&#xff0c;如…

Java 第19章 IO流 课堂练习+本章作业

文章目录 Buffered流拷贝二进制文件创建文件写入文本读取文本文件存读Properties文件 Buffered流拷贝二进制文件 package com.hspedu.chapter19.outputStream;import java.io.*;public class BufferedCopy02 {public static void main(String[] args) {String srcFilePath &q…

大创项目推荐 深度学习人脸表情识别算法 - opencv python 机器视觉

文章目录 0 前言1 技术介绍1.1 技术概括1.2 目前表情识别实现技术 2 实现效果3 深度学习表情识别实现过程3.1 网络架构3.2 数据3.3 实现流程3.4 部分实现代码 4 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习人脸表情识别系…

redis 三主六从高可用dockerswarm高级版(不固定ip)

redis集群(cluster)笔记 redis 三主三从高可用集群docker swarm redis 三主六从高可用docker(不固定ip) redis 三主六从高可用dockerswarm高级版(不固定ip) 此博客解决&#xff0c;redis加入集群后&#xff0c;是用于停掉后重启&#xff0c;将nodes.conf中的旧的Ip替换为新的…

docker搭建Dinky —— 筑梦之路

简介 Dinky 是一个 开箱即用 、易扩展 &#xff0c;以 Apache Flink 为基础&#xff0c;连接 OLAP 和 数据湖 等众多框架的 一站式 实时计算平台&#xff0c;致力于 流批一体 和 湖仓一体 的探索与实践。 主要功能 其主要功能如下&#xff1a; 沉浸式 FlinkSQL 数据开发&#x…

PHP开发日志 ━━ 基于PHP和JS的AES相互加密解密方法详解(CryptoJS) 适合CryptoJS4.0和PHP8.0

最近客户在做安全等保&#xff0c;需要后台登录密码采用加密方式&#xff0c;原来用个base64变形一下就算了&#xff0c;现在不行&#xff0c;一定要加密加key加盐~~ 前端使用Cypto-JS加密&#xff0c;传输给后端使用PHP解密&#xff0c;当然&#xff0c;前端虽然有key有盐&…

书生-浦路大模型全链路开源体系

2023年&#xff0c;大模型成为热门关键词 论文链接 大模型已经成为发展通用人工智能的重要途经 模型评测过程&#xff1a;从模型到应用 全链条开源开发体系 | 数据&#xff1a; 多模态融合 万卷包含文本、图像和视频等多模态数据&#xff0c;涵盖科技、文学、媒体、教育和法…

奋楫扬帆,奔赴新程 | 2023 年图扑大事记回顾,与您携手共迎 2024

2023.01 工信部公示了 2022 年度智能制造示范工厂揭榜单位和优秀场景名单。图扑软件和上海洲邦合作建设的宁波甬友数字孪生工厂被评为优秀场景&#xff0c;全国共有 369 个智能制造典型场景入选。 2023.01 在第十一届中国创新创业大赛全国赛&#xff08;新一代信息技术&#…

react+redux+antd-mobile 之 记账本案例

1.环境搭建 //使用CRA创建项目&#xff0c;并安装必要依赖&#xff0c;包括下列基础包 //1. Redux状态管理 - reduxjs/toolkit 、 react-redux //2. 路由 - react-router-dom //3. 时间处理 - dayjs //4. class类名处理 - classnames //5. 移动端组件库 - antd-mobile //6. 请…

SAP badi增强查找

查找SAP BADI的方法. 1. 通过SE24 查找. 输入 CL_EXITHANDLER, 双击 GET_INTANCE. 设定断点. 执行Tcode, 当有出口时, 程式会自动进入Debug界面. 观察 EXIT_NAME的值. 2. 同样可能SE80中通过Package查找. 3. 通过ST05 追踪, BADI对应的数据表为 SXS_INTER, SXC_EXIT, SXC…