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状态管理的基本使用了,在项目中会经常用到喔✌

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

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

相关文章

软件测试/测试开发丨Python学习笔记之基本数据类型与操作

一、变量 1、变量的定义: a. 在python中,变量是一种存储数据的载体。计算机中的变量是实际存在的数据或者说是存储器中存储数据的一块内存空间; b.变量的值可以被读取和修改。 2、命名规则: a.变量名由字母(广义的Unic…

揭秘代理IP服务:选择、测试与优化的全面指南

代理IP服务是一种重要的网络工具,它通过中间的代理服务器来转发用户的网络请求,从而隐藏用户的原始IP地址。以下是一个全面的指南,涵盖了选择、测试和优化代理IP服务的关键步骤: 1. 理解需求: 确定使用代理IP的目的&am…

第一节 初始化项目

系列文章目录 第一节 初始化项目 文章目录 操作步骤 总结 操作步骤 打开cmd 输入 vue ui 在打开的网页中点击“创建”,复制文件夹路径并粘贴点击“在此创建新项目” 输入项目名称 点击下一步选择手动配置 选择babel、router、vuex、css pre-processors、 linter建…

Arduino平台软硬件原理及使用——发光二极管(LED灯)的使用

文章目录 一、发光二极管的发光原理 二、发光二极管正负极的辨别 三、发光二极管在Arduino中的使用 一、发光二极管的发光原理 通过上述两幅图像对发光二极管的结构及发光原理进行理解; 从物理学的角度而言,当电流通过晶片时(N区的电子向P区移…

腾讯云轻量应用服务器详细介绍

腾讯云轻量应用服务器开箱即用、运维简单的轻量级云服务器,CPU内存带宽配置高并且价格特别优惠,轻量2核2G3M带宽62元一年、2核2G4M优惠价118元一年,540元三年、2核4G5M带宽218元一年,756元3年、4核8G12M带宽646元15个月等&#xf…

RustDesk连接客户端提示key不匹配 Key Mismatch无法连接(已解决)

环境: RustDesk1.1.9 服务端docker部署 问题描述: RustDesk连接客户端提示key不匹配 Key Mismatch无法连接 解决方案: 1.docker部署RustDesk服务检查配置 networks:rustdesk-net:external: falsevolumes:hbbr:hbbs:services:hbbs:container_name: rustdesk-hbbsport…

数模学习day03-层次分析法代码

这篇文章也是来到了第一讲层次分析法的最后一节,准备浅浅的撒花花吧~~~ 进入正题 1.判断矩阵计算权重 计算判断矩阵的时候,要先填好这个矩阵是吧,但是要求是让专家填,但是由于咱学生一般是请不到专家来的,所以说就咱…

【unity3D-粒子系统】粒子系统主模块-Particle System篇

💗 未来的游戏开发程序媛,现在的努力学习菜鸡 💦本专栏是我关于游戏开发的学习笔记 🈶本篇是unity的粒子系统主模块-Particle System 基础知识 Particle System 介绍:粒子系统的主模块,是必需的模块&#x…

Vue3-27-路由-路径参数的简单使用

什么是路径参数 在路由配置中,可以将【参数】放在【路由路径】中, 从而实现,同一个 路由,同一个组件,因路径参数不同,可以渲染出不同的内容。特点 : 1、当携带不同路径参数的路由相互跳转时&am…

泰迪智能科技分享:AI大模型发展趋势分析

大规模预训练语言模型,也被称为“大模型”或“基座模型”,其特点在于拥有巨大的参数量,构成了复杂的人工神经网络模型。大模型具有规模性(参数量大)、涌现性(产生预料之外的新能力)以及通用性&a…

【mac-m1 docker 安装upload-labs靶场】

1.搜索upload-labs docker search upload-labs 2.下载upload-labs docker pull c0ny1/upload-labs 3.启动 docker run -it -d --name uploadlabs -p 80:80 c0ny1/upload-labs --platform linux/amd64 4.访问127.0.0.1:80

自定义docker镜像,ubuntu安装命令并导出

文章目录 问题现象解决步骤相关命令详细介绍docker save 与 docker loaddocker import 与 docker exportdocker commit 问题现象 我们的通讯服务,需要监测前端设备的在线情况(是否在线、丢包率、延迟等),使用ping命令去实现此功能…

Spring Boot项目Jar包加密:防止反编译的安全实践

文章目录 1. 引言2. 背景3. Jar包加密方案3.1 使用Java混淆工具3.2 使用Jar包加密工具3.2.1 示例:使用JCryptor对Jar包进行加密 4. 加密后的Jar包的运行5. 安全性与性能考虑5.1 安全性考虑5.2 性能考虑 6. 拓展功能与未来展望6.1 数字签名与验签6.2 使用加密算法库 …

使用克魔助手进行iOS数据抓包和HTTP抓包的方法详解

摘要 本文博客将介绍如何在iOS环境下使用克魔助手进行数据抓包和HTTP抓包。通过抓包,开发者可以分析移动应用程序的网络请求发送和接收过程,识别潜在的性能和安全问题,提高应用的质量和安全性。 引言 在移动应用程序的开发和测试过程中&am…

畅捷通的 Serverless 探索实践之路

作者:计缘,阿里云云原生架构师 畅捷通介绍 畅捷通是中国领先的小微企业财税及业务云服务提供商,成立于 2010 年。畅捷通在 2021 年中国小微企业云财税市场份额排名第一,在产品前瞻性及行业全覆盖方面领跑市场,位居中…

打开相机失败 出现错误的原因

如何解决? Debug中缺少DLL文件 以下参考周姐文档 相机调用步骤 学习相机第三方库的安装 https://blog.csdn.net/Qingshan_z/article/details/117257136书签:QT添加库(静态库和动态库)_Qingshan_z的博客-CSDN博客_qt添加库 添加文…

Python 爬虫 小案例 之 快手下载视频

前言 大家早好、午好、晚好吖 ❤ ~欢迎光临本文章 如果有什么疑惑/资料需要的可以点击文章末尾名片领取源码 知识点: 动态数据抓包 requests发送请求开发环境: python 3.8 运行代码 pycharm 2022.3 辅助敲代码 requests pip insta…

电脑怎么设置代理IP上网?如何隐藏自己电脑的真实IP?

在现代互联网中,代理IP已成为许多用户保护隐私和上网安全的重要手段。通过设置代理IP,用户可以隐藏自己的真实IP地址,提高上网的安全性,同时保护个人信息不被泄露。本文将详细介绍如何设置代理IP上网以及如何隐藏电脑的真实IP地址…

K8s实战-init容器

概念: 初始化容器的概念 比如一个容器A依赖其他容器,可以为A设置多个 依赖容易A1,A2,A3 A1,A2,A3要按照顺序启动,A1没有启动启动起来的 话,A2,A3是不会启动的,直到所有的静态容器全 部启动完毕…

【已解决】taos时序数据库3.0版本,怎么按照时间分组?

taos数据库中按照时间分组,在2.4版本时候可以直接使用INTERVAL(time_unit)来查询。例如 前面可以直接添加_ts的。但是在3.0版本之后,如果直接使用的话,只会返回count: 没有前面的时间。那么在3.0版本时候,怎么修改呢&a…