HarmonyOS4.0开发应用(四)【ArkUI状态管理】
ArkUI状态管理
分为以下四个:
- @State
- @Prop和@Link
- @Provide和@Consume
- @Observed和@ObjectLink
@State
相当于
vue中data()内定义的属性变量,相当于react中useState()的使用,即绑定在视图上的响应式变量,可动态更新~
Tip:
- 标记的变量必须初始化,不可为空值
- 支持Object、class、string、number、boolean、enum类型以及这些类型的数组
- 嵌套类型以及数组中的对象属性无法触发视图更新(类似于vue2中更改数组无法触发更新)
实操使用@State状态管理变量,实现一个任务进度案例(类似todo)

// 实现案例:任务统计
class Task{static id: number=1name: string='任务'+Task.id++isok: boolean =false
}
//卡片样式
@Styles function card(){.width('95%').padding(20).backgroundColor(Color.White).borderRadius(15).shadow({radius:6 , color: '#1F000000',offsetX:2,offsetY:4})
}
//完成样式(继承Text标签的样式属性)
@Extend(Text) function okTask(){.decoration({type:TextDecorationType.LineThrough}).fontColor('#B1B2B1')
}
@Entry
@Component
struct RwtjPage {@State totalTask: number = 0@State okTask:number = 0@State tasks: Task[]=[]handlerTaskChange(){this.tasks.push(new Task())this.tasks.pop()//更新进度this.totalTask=this.tasks.lengththis.okTask=this.tasks.filter(ok=>ok.isok).length//返回为true的数组列表的长度}build() {Column({space:10}) {//任务进度Row(){Text('任务进度:').fontSize(30).fontWeight(FontWeight.Bold)Stack(){//叠加容器Progress({value:this.okTask,total:this.totalTask,type:ProgressType.Ring}).width(100)Row() {Text(this.okTask.toString()).fontSize(24).fontColor("#36D")Text('/' + this.totalTask.toString()).fontSize(24)}}}.card().margin({top:20,bottom:10}).justifyContent(FlexAlign.SpaceEvenly)//新增任务Button('Add 任务').width(200).onClick(()=>{this.tasks.push(new Task())this.handlerTaskChange()})List({space:10}){//渲染任务列表ForEach(this.tasks,(item:Task,index)=>{ListItem(){Row(){if(item.isok===true){Text(item.name).fontSize(20).okTask()}else{Text(item.name).fontSize(20)}Checkbox().select(item.isok).onChange(val=>{item.isok=valthis.handlerTaskChange()})}.card().justifyContent(FlexAlign.SpaceBetween)}.swipeAction({end:this.DeleteBtn(index)}) //listitem自带的属性})}.width("100%").layoutWeight(1).alignListItem(ListItemAlign.Center)}.width('100%').height('100%').backgroundColor('#F1F2F3')}@Builder DeleteBtn(index: number){Button('Del').backgroundColor('red').fontColor('#fff').onClick(()=>{this.tasks.splice(index,1)this.handlerTaskChange()})}
}
@Prop和@Link
用于父子组件数据同步
- 可以将上方案例拆分为组件式便于代码解读维护
| @Prop | @Link | |
|---|---|---|
| 同步类型 | 单向 | 双向 |
| 允许装饰的变量类型 | @Prop只支持: string、number、boolean、enum类型 父组件对象类型,子组件是对象屈性 不可以是数组、any | 父子类型一致: string、number、boolean、enum、object、class,以及他们的数组数组中元素增、删、替换会引起刷新嵌套类型以及数组中的对象属性无法触发视图更新 |
| 初始化方式 | 不允许子组件初始化和 | 父组件传递,禁止子组件初始化 |
// 实现案例:任务统计
class Task{static id: number=1name: string='任务'+Task.id++isok: boolean =false
}
//卡片样式
@Styles function card(){.width('95%').padding(20).backgroundColor(Color.White).borderRadius(15).shadow({radius:6 , color: '#1F000000',offsetX:2,offsetY:4})
}
//完成样式(继承Text标签的样式属性)
@Extend(Text) function okTask(){.decoration({type:TextDecorationType.LineThrough}).fontColor('#B1B2B1')
}
@Entry
@Component
struct RwtjPage {@State totalTask: number = 0@State okTask:number = 0// @State tasks: Task[]=[]build() {Column({space:10}) {//任务进度TaskStatistics({okTask:this.okTask,totalTask:this.totalTask})//任务列表TaskList({okTask:$okTask,totalTask:$totalTask})}.width('100%').height('100%').backgroundColor('#F1F2F3')}
}@Component
struct TaskStatistics{@Prop okTask:number@Prop totalTask:numberbuild(){Row(){Text('任务进度:').fontSize(30).fontWeight(FontWeight.Bold)Stack(){//叠加容器Progress({value:this.okTask,total:this.totalTask,type:ProgressType.Ring}).width(100)Row() {Text(this.okTask.toString()).fontSize(24).fontColor("#36D")Text('/' + this.totalTask.toString()).fontSize(24)}}}.card().margin({top:20,bottom:10}).justifyContent(FlexAlign.SpaceEvenly)}
}@Component
struct TaskList{@Link okTask:number@Link totalTask:number@State tasks:Task[]=[]handlerTaskChange(){this.tasks.push(new Task())this.tasks.pop()//更新进度this.totalTask=this.tasks.lengththis.okTask=this.tasks.filter(ok=>ok.isok).length//返回为true的数组列表的长度}build(){Column(){//新增任务Button('Add 任务').width(200).onClick(()=>{this.tasks.push(new Task())this.handlerTaskChange()})List({space:10}){//渲染任务列表ForEach(this.tasks,(item:Task,index)=>{ListItem(){Row(){if(item.isok===true){Text(item.name).fontSize(20).okTask()}else{Text(item.name).fontSize(20)}Checkbox().select(item.isok).onChange(val=>{item.isok=valthis.handlerTaskChange()})}.card().justifyContent(FlexAlign.SpaceBetween)}.swipeAction({end:this.DeleteBtn(index)}) //listitem自带的属性})}.width("100%").layoutWeight(1).alignListItem(ListItemAlign.Center)}}@Builder DeleteBtn(index: number){Button('Del').backgroundColor('red').fontColor('#fff').onClick(()=>{this.tasks.splice(index,1)this.handlerTaskChange()})}
}
@Provide和@Consume
可以跨组件提供类似于
@State和@Link的双向同步
- 用了感觉更省事,同时也会更消耗资源
用@Link双向同步:
@State totalTask: number = 0@State okTask:number = 0// @State tasks: Task[]=[]build() {Column({space:10}) {//任务列表TaskList({okTask:$okTask,totalTask:$totalTask})}.width('100%').height('100%').backgroundColor('#F1F2F3')}
@Component
struct TaskList{@Link okTask:number@Link totalTask:number@State tasks:Task[]=[]handlerTaskChange(){this.tasks.push(new Task())this.tasks.pop()//更新进度this.totalTask=this.tasks.lengththis.okTask=this.tasks.filter(ok=>ok.isok).length//返回为true的数组列表的长度}build(){Column(){......}
}
用@Provide和@Consume双向同步:
@ProvidetotalTask: number = 0@ProvideokTask:number = 0// @State tasks: Task[]=[]build() {Column({space:10}) {//任务列表TaskList()}.width('100%').height('100%').backgroundColor('#F1F2F3')}
@Component
struct TaskList{@Consume okTask:number@Consume totalTask:number@State tasks:Task[]=[]handlerTaskChange(){this.tasks.push(new Task())this.tasks.pop()//更新进度this.totalTask=this.tasks.lengththis.okTask=this.tasks.filter(ok=>ok.isok).length//返回为true的数组列表的长度}build(){Column(){......}
}
区别: 不用手动传参了,自动化~
@Observed和@ObjectLink
用于涉及
嵌套对象和数组元素对象的场景中进行双向数据同步
- 上方案例的下划线功能就是因为修改了数组元素数组没渲染导致更新状态没有第一时间改变视图(然后我通过修改数组长度,push再删除,解决了这个问题,现在可以使用@Observed和@ObjectLink方式解决该问题)
可再次基于上次案例进行改进实现
// 实现案例:任务统计
@Observed
class Task{static id: number=1name: string='任务'+Task.id++isok: boolean =false
}
//卡片样式
@Styles function card(){.width('95%').padding(20).backgroundColor(Color.White).borderRadius(15).shadow({radius:6 , color: '#1F000000',offsetX:2,offsetY:4})
}
//完成样式(继承Text标签的样式属性)
@Extend(Text) function okTask(){.decoration({type:TextDecorationType.LineThrough}).fontColor('#B1B2B1')
}
@Entry
@Component
struct RwtjPage {@Provide totalTask: number = 0@Provide okTask:number = 0// @State tasks: Task[]=[]build() {Column({space:10}) {//任务进度TaskStatistics()//任务列表TaskList()}.width('100%').height('100%').backgroundColor('#F1F2F3')}
}@Component
struct TaskStatistics{@Consume okTask:number@Consume totalTask:numberbuild(){Row(){Text('任务进度:').fontSize(30).fontWeight(FontWeight.Bold)Stack(){//叠加容器Progress({value:this.okTask,total:this.totalTask,type:ProgressType.Ring}).width(100)Row() {Text(this.okTask.toString()).fontSize(24).fontColor("#36D")Text('/' + this.totalTask.toString()).fontSize(24)}}}.card().margin({top:20,bottom:10}).justifyContent(FlexAlign.SpaceEvenly)}
}@Component
struct TaskList{@Consume okTask:number@Consume totalTask:number@State tasks:Task[]=[]handlerTaskChange(){// this.tasks.push(new Task())// this.tasks.pop()//更新进度this.totalTask=this.tasks.lengththis.okTask=this.tasks.filter(ok=>ok.isok).length//返回为true的数组列表的长度}build(){Column(){//新增任务Button('Add 任务').width(200).onClick(()=>{this.tasks.push(new Task())this.handlerTaskChange()})List({space:10}){//渲染任务列表ForEach(this.tasks,(item:Task,index)=>{ListItem(){TaskItem({item:item,onTaskChange:this.handlerTaskChange.bind(this)})}.swipeAction({end:this.DeleteBtn(index)}) //listitem自带的属性})}.width("100%").layoutWeight(1).alignListItem(ListItemAlign.Center)}}@Builder DeleteBtn(index: number){Button('Del').backgroundColor('red').fontColor('#fff').onClick(()=>{this.tasks.splice(index,1)this.handlerTaskChange()})}
}@Component
struct TaskItem {@ObjectLink item: TaskonTaskChange: ()=>voidbuild() {Row(){if(this.item.isok===true){Text(this.item.name).fontSize(20).okTask()}else{Text(this.item.name).fontSize(20)}Checkbox().select(this.item.isok).onChange(val=>{this.item.isok=valthis.onTaskChange()// this.handlerTaskChange()})}.card().justifyContent(FlexAlign.SpaceBetween)}
}
上方主要是在
Task类加上@Observed,其次传递函数的时候需要加个.bind(this)表示函数指向本方法
- 再通过组件中使用
@ObjectLink实现接收传来的数组中对象,通过修改对象中的属性从而视图跟着刷新,替换了我的小聪明代码
// this.tasks.push(new Task()) // this.tasks.pop()
通过以上内容即可学会
ArkUI状态管理的基本使用了,在项目中会经常用到喔✌
相关文章:
HarmonyOS4.0开发应用(四)【ArkUI状态管理】
ArkUI状态管理 分为以下四个: StateProp和LinkProvide和ConsumeObserved和ObjectLink State 相当于vue中data()内定义的属性变量,相当于react中useState()的使用,即绑定在视图上的响应式变量,可动态更新~ Tip: 标记的变量必须初始化,不可为空…...
JS常见正则表达式写法(附案例)
正则表达式方法示例: 1. test方法解析,test判断正则是否在字符串中出现过,如果出现返回true,如果没出现返回false。 let str hello world; let ret1 /e/.test(str); // true let ret2 /q/.test(str); // false 如&…...
go语言,ent库与gorm库,插入一条null值的time数据
情景介绍 使用go语言,我需要保存xxxTime的字段至数据库中,这个字段可能为空,也可能是一段时间。我采取的是统一先赋值为空,若有需要,则再进行插入(需要根据另一个字段判断是否插入) 在我的数据…...
Java EasyExcel 导入代码
Java EasyExcel 导入代码 导入方法 /*** 仓库库位导入** param req* param res* param files* throws Exception*/RequestMapping(value {"/import/line_store_locs"}, method {RequestMethod.POST})ResponseBodypublic void importStoreLoc(HttpServletRequest …...
2024,5G-A风起,中兴通讯破浪
对于通信圈而言,2024年最关键的里程碑,当属3GPP R18版本即将冻结。作为5G国际标准化组织,3GPP的意义是推动成员公司、工作组和技术规范的研究,让5G发展更有章法。 放眼整个5G技术的演进,其实大致分为两个阶段。第一阶段…...
SuperMap Hi-Fi 3D SDK for Unity矢量面贴地贴模型
作者:kele 一、背景 SuperMap Hi-Fi 3D SDK(2023 11i) for Unity推出新功能:支持矢量面同时贴地形图层和模型图层,并且能实现数据点击查询属性、更改初始填充颜色、初始边框线颜色、选中填充颜色、选中边框线颜色、控…...
【DB2】Maxlocks和防止锁升级
数据库在对行操作的时候,为了避免多个作业互相覆盖影响数据准确性,在进行操作(尤其是写操作)的时候会上锁,同一时间只有一个作业可以修改数值 对行上锁,为了记录锁的信息,所以会占用一定的内存…...
网工内推 | 网络服务工程师,HCIE认证优先,带薪年假,年终奖
01 高凌信息 招聘岗位:服务工程师(珠海) 职责描述: 1、负责华为数通(交换机、路由器)、IT(服务器、存储)等任一或多个产品领域的项目实施交付; 2、独立完成华为数通&…...
TrustZone之可信固件
Trusted Firmware是Armv8-A设备的安全世界软件的开源参考实现。Trusted Firmware为SoC开发人员和OEM提供了一个符合相关Arm规格(包括TBBR和SMCC)的参考Trusted代码库。 以下图表显示了Trusted Firmware的结构: SMC调度程序处理传入的SMC。SMC…...
Visual Studio 2013 中创建一个基于 Qt 的动态链接库:并在MFC DLL程序中使用
在本地已经安装好 Qt 的情况下,按照以下步骤在 Visual Studio 2013 中创建一个基于 Qt 的动态链接库: 一、新建 Qt 项目: 在 Visual Studio 中,选择 “文件” -> “新建” -> “项目…”。在 “新建项目” 对话框中&#…...
云计算:OpenStack 配置云主机实例的资源实现内网互通
目录 一、实验 1. 环境 2.配置项目及用户 3.配置规格实例与镜像 4.配置VPC 5. 配置安全组 6. 创建云主机 cs_01 (cirros系统) 7.创建云主机 cs_02 (cirros系统) 一、实验 1. 环境 (1)宿主机 表1…...
Android原生实现单选
六年前写的一个控件,一直没有时间总结,趁年底不怎么忙,整理一下之前写过的组件。供大家一起参考学习。废话不多说,先上图。 一、效果图 实现思路使用的是radioGroup加radiobutton组合方式。原理就是通过修改RadioButton 的backgr…...
为什么需要对数值类型的特征做归一化?
对数值类型的特征做归一化可以将所有的特征都统一到一个大致相同的数值区间内。最常用的方法有以下两种: (1)线性函数归一化(Min-Max Scaling) 它对原始数据进行线性变换,使结果映射到【0,1】的范围&…...
ARM 点灯
.text .global _start _start: led1设置GPIOE时钟使能 RCC_MP_AHB4ENSETR[4]->1 0X50000A28LDR R0,0X50000A28 指定寄存器地址LDR R1,[R0] 将寄存器数值取出来放在R1中ORR R1,R1,#(0x1<<4) 将第4位设置为1STR R1,[R0] 将修改后的值写回去设置PE10为输出 GPIOE…...
CamSim相机模拟器:极大加速图像处理开发与验证过程
随着图像处理技术的不断发展,相机模拟在图像处理开发和验证中扮演着越来越重要的角色。相机模拟能够模拟真实相机的成像过程,提供高质量的图像输入,使开发人员能够更好地评估和调整图像处理算法。本文将探讨如何通过相机模拟来加速图像处理的…...
Google Ad帐号被封?代理IP和电子邮件可能是原因
海外广告投放工作中,账号是非常重要的环节。与在Facebook上运行广告相比,运行Google Ads在代理选择方面通常没有那么严格,因为 Google 对 IP 使用并不那么严格。但是,这并不意味着您可以不加考虑地使用任何代理IP。在本文中&#…...
EfficientNet
时间:2019 EfficicentNet网络简介 EfficientNet:Rethinking Model Scaling for Convolutional Neural Networkshttps://arxiv.org/abs/1905.11946,这篇论文是Google在2019年发表的文章。 EfficientNet这篇论文,作者同时关于输入分辨率,网络…...
百度每天20%新增代码由AI生成,Comate SaaS服务8000家客户 采纳率超40%
12月28日,由深度学习技术及应用国家工程研究中心主办的WAVE SUMMIT深度学习开发者大会2023在北京召开。百度首席技术官、深度学习技术及应用国家工程研究中心主任王海峰现场公布了飞桨文心五载十届最新生态成果,文心一言最新用户规模破1亿,截…...
产品管理-学习笔记-版本的划分
版本号说明【X.Y.Z_修饰词】 版本号定义原则X表示大版本号,一般当产品出现重大更新、调整、不再向后兼容的情况时我们会在X上加1Y表示功能更新,在产品原有的基础上增加、修改部分功能,且并不影响产品的整体流程或业务Z表示小修改,…...
编程笔记 html5cssjs 004 我的第一个页面
编程笔记 html5&css&js 004 我的第一个页面 一、基本结构二、HTML标签三、HTML元素四、HTML属性五、编写第一个网页六、使用VSCODE小结 开始编写网页,并且使用第一个网页成为一个母板,用于完成后续内容的学习。有一个基本要求,显示结…...
探索基于Cruise与Simulink的前后双电机纯电动汽车联合仿真
基于Cruise和Simulink联合仿真前后双电机纯电动汽车模型,包含驱动转矩控制策略和最优转矩分配分配系数的dll文件,可根据自身车辆参数修改相关参数在电动汽车的研发领域,联合仿真技术正逐渐成为提升性能与优化设计的关键手段。今天咱就来唠唠基…...
OpenClaw技能开发指南:为Qwen3.5-4B-Claude定制专属自动化
OpenClaw技能开发指南:为Qwen3.5-4B-Claude定制专属自动化 1. 为什么需要自定义Skill? 去年我接手了一个重复性极高的数据整理工作——每天要从十几个气象网站抓取数据,手动整理成Excel报表。当我第三次在凌晨两点对着屏幕核对数据时&#…...
如何快速优化AMD系统:5个实用技巧让Ryzen性能更稳定
如何快速优化AMD系统:5个实用技巧让Ryzen性能更稳定 【免费下载链接】SMUDebugTool A dedicated tool to help write/read various parameters of Ryzen-based systems, such as manual overclock, SMU, PCI, CPUID, MSR and Power Table. 项目地址: https://gitc…...
PvZ Toolkit终极指南:植物大战僵尸PC版免费完整修改器快速上手
PvZ Toolkit终极指南:植物大战僵尸PC版免费完整修改器快速上手 【免费下载链接】pvztoolkit 植物大战僵尸 PC 版综合修改器 项目地址: https://gitcode.com/gh_mirrors/pv/pvztoolkit 还在为植物大战僵尸中的资源匮乏而烦恼吗?PvZ Toolkit这款开源…...
电子萌新必看!用TXS0102芯片搞定3.3V/5V电平转换的5种典型电路
电子萌新必看!用TXS0102芯片搞定3.3V/5V电平转换的5种典型电路 第一次用Arduino连接5V传感器时,看到串口数据全是乱码的崩溃感,相信很多硬件爱好者都经历过。这种"电压鸿沟"问题在混合使用3.3V和5V设备时尤为常见,而TXS…...
别再被NFS的‘非法端口’拦住了!手把手教你用insecure选项解决mount.nfs: access denied
突破NFS端口限制:深入解析insecure选项的实战应用 上周在调试一个嵌入式开发环境时,遇到了一个典型的NFS挂载问题。当我在VirtualBox虚拟机中尝试挂载物理机上的NFS共享目录时,终端突然弹出mount.nfs: access denied by server while mountin…...
**发散创新:用Rust构建Web3.0去中心化身份(DID)验证服务**在Web3.0时代,用户不再依赖中心化的身份提供商(
发散创新:用Rust构建Web3.0去中心化身份(DID)验证服务 在Web3.0时代,用户不再依赖中心化的身份提供商(如Google、微信登录),而是通过去中心化身份(Decentralized Identity, DID&…...
从libdatachannel到AioRTC:构建轻量级WebRTC原型实践指南
1. 为什么选择libdatachannel和AioRTC 最近在研究浏览器音视频流推送技术时,我发现WebRTC虽然强大但入门门槛较高。经过多轮技术选型对比,最终锁定了两个轻量级开源库:C的libdatachannel和Python的AioRTC。这两个项目特别适合快速原型开发&am…...
从图片预览需求看H5监听浏览器返回事件的3种实现方案(含history API避坑指南)
从图片预览需求看H5监听浏览器返回事件的3种实现方案(含history API避坑指南) 在移动端H5开发中,图片预览功能几乎是标配需求。随着全面屏手势操作的普及,用户越来越习惯通过滑动返回退出预览,而非点击关闭按钮。这种交…...
别再让输入框‘抢焦点’了!手把手封装一个Vue扫码枪工具类SCAN,解决页面刷新监听丢失
从零构建高可靠Vue扫码枪工具库:SCAN类深度封装与工程化实践 扫码枪在零售、仓储、医疗等行业的Web系统中应用广泛,但传统实现强依赖输入框焦点,用户体验差且稳定性低。本文将带你从底层原理出发,完整封装一个无需输入框聚焦、支持…...
