HarmonyOS4.0开发应用(四)【ArkUI状态管理】

news2025/1/20 2:02:18

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=1
  name: 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.length
    this.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=val
                      this.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=1
  name: 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:number
  build(){
    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.length
    this.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=val
                    this.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.length
    this.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.length
    this.okTask=this.tasks.filter(ok=>ok.isok).length//返回为true的数组列表的长度
  }
  build(){
    Column(){
     ......
  }
}

区别: 不用手动传参了,自动化~

@Observed和@ObjectLink

用于涉及嵌套对象数组元素对象的场景中进行双向数据同步

  • 上方案例的下划线功能就是因为修改了数组元素数组没渲染导致更新状态没有第一时间改变视图(然后我通过修改数组长度,push再删除,解决了这个问题,现在可以使用@Observed和@ObjectLink方式解决该问题)

可再次基于上次案例进行改进实现

// 实现案例:任务统计
@Observed
class Task{
  static id: number=1
  name: 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:number
  build(){
    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.length
    this.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: Task
  onTaskChange: ()=>void
  build() {
    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=val
          this.onTaskChange()
          // this.handlerTaskChange()
        })
    }
    .card()
    .justifyContent(FlexAlign.SpaceBetween)
  }
}

上方主要是在Task类加上@Observed,其次传递函数的时候需要加个.bind(this)表示函数指向本方法

  • 再通过组件中使用@ObjectLink实现接收传来的数组中对象,通过修改对象中的属性从而视图跟着刷新,替换了我的小聪明代码
    // this.tasks.push(new Task()) // this.tasks.pop()

通过以上内容即可学会ArkUI状态管理的基本使用了,在项目中会经常用到喔✌

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

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

相关文章

手把手带你开发Cesium三维场景【3D智慧城市警情预警】

📢 鸿蒙专栏:想学鸿蒙的,冲 📢 C语言专栏:想学C语言的,冲 📢 VUE专栏:想学VUE的,冲这里 📢 CSS专栏:想学CSS的,冲这里 &#x1f4…

LabVIEW利用视觉引导机开发器人精准抓取

LabVIEW利用视觉引导机开发器人精准抓取 本项目利用单目视觉技术指导多关节机器人精确抓取三维物体的技术。通过改进传统的相机标定方法,结合LabVIEW平台的Vision Development和Vision Builder forAutomated Inspection组件,优化了摄像系统的标定过程&a…

使用机器学习进行语法错误检测/纠正

francescofranco_39234 一、说明 一般的学习,特别是深度学习,促进了自然语言处理。各种模型使人们能够执行机器翻译、文本摘要和情感分析——仅举几个用例。今天,我们将研究另一个流行的用途:我们将使用Gramformer构建一个用于机器…

传统船检已经过时?AR智慧船检来助力!!

想象一下,在茫茫大海中,一艘巨型货轮正缓缓驶过。船上的工程师戴着一副先进的AR眼镜,他们不再需要反复翻阅厚重的手册,一切所需信息都实时显示在眼前。这不是科幻电影的场景,而是智慧船检技术带来的现实变革。那么问题…

VMware之FTP的简介以及搭建计算机端口的介绍

目录 一.FTP的简介 1.1 FTP的作用 二.FTP的搭建 2.1 建立组和用户 2.2 添加角色和功能 2.3 用户绑定组 2.4 配置FTP服务器 2.5 授权 2.5 连接测试 三.计算机端口介绍 3.1 端口分类: 3.2 常见的计算机端口及其用途: 四.附图-思维…

C语言使用蔡勒公式判断日期的星期

引言 在日常编程中,处理日期和时间是一个常见的任务。而了解一个特定日期是星期几,是许多应用程序中的一个基本需求。本篇博客将深入解析一个用于计算星期的 C 语言函数。 代码概览 这个函数使用了蔡勒公式来实现,蔡勒公式(Zel…

启明智显开源项目分享|基于Model 3c芯片的86中控面板ZX3D95CM20S-V11项目软硬件全开源

前言: 本文为4寸 480*480 RGB接口IPS全面触屏的86中控面板(RT-ThreadLVGL)软硬件开源干货内容,该项目是综合性非常强的RTOS系列项目!项目主控芯片使用 Model 3c,整体实现了简化版本的86中控面板的功能需求…

EDA巨头千亿级收购案谈判中 | 百能云芯

近期传出消息,电子设计自动化(EDA)领域的巨头新思科技(Synopsys)已向计算机辅助工程(CAE)软件行业的领导者安世(Ansys)递交了一份收购要约。据悉,新思科技的报…

快速排序:高效分割与递归,排序领域的王者算法

🎬 鸽芷咕:个人主页 🔥 个人专栏: 《数据结构&算法》《粉丝福利》 ⛺️生活的理想,就是为了理想的生活! 📋 前言 快速排序这个名词,快排之所以叫快排肯定是有点东西的。他在处理大规模数据集时表现及其…

处理urllib.request.urlopen报错UnicodeEncodeError:‘ascii‘

参考:[Python3填坑之旅]一urllib模块网页爬虫访问中文网址出错 目录 一、报错内容 二、报错截图 三、解决方法 四、实例代码 五、运行截图 六、其他UnicodeEncodeError: ascii codec 问题 一、报错内容 UnicodeEncodeError: ascii codec cant encode charac…

缓存和缓冲的区别

近期被这两个词汇困扰了,感觉有本质的区别,搜了一些资料,整理如下 计算机内部的几个部分图如下 缓存(cache) https://baike.baidu.com/item/%E7%BC%93%E5%AD%98 提到缓存(cache),就…

【LeetCode-剑指offer】--3.比特位计数

3.比特位计数 class Solution {public int[] countBits(int n) {int[] bites new int[n 1];for(int i 0 ; i < n;i){bites[i] Count(i);}return bites;}public int Count(int x){int count 0;while(x > 0){x & (x - 1);count;}return count;} }

【SVN】Windows版合并提交bat文件+自定义菜单快捷键

【工具向】利用bat批处理打开TortoiseGit简化版本管理流程_tortoisegit bat-CSDN博客 start cmd /k "cd C:\YourBranchProj && svn cleanup && svn update && svn merge C:\YourTrunkProj -r 历史版本号:HEAD && svn commit -m "me…

项目接口性能优化方案

&#x1f9d1;‍&#x1f4bb;作者名称&#xff1a;DaenCode &#x1f3a4;作者简介&#xff1a;CSDN实力新星&#xff0c;后端开发两年经验&#xff0c;曾担任甲方技术代表。会点点Java相关技术栈、帆软报表、低代码平台快速开发。技术尚浅&#xff0c;闭关学习中 &#x1f60…

论文阅读《Restormer: Efficient Transformer for High-Resolution Image Restoration》

论文地址:https://openaccess.thecvf.com/content/CVPR2022/html/Zamir_Restormer_Efficient_Transformer_for_High-Resolution_Image_Restoration_CVPR_2022_paper.html 源码地址:https://github.com/swz30/Restormer 概述 图像恢复任务旨在从受到各种扰动(噪声、模糊、雨滴…

低延时视频技术的应用场景和挑战

编者按 无线网络对人们的生活产生了巨大的影响&#xff0c;而5G技术的引入将彻底改变我们与世界互联互通的方式。在5G时代&#xff0c;实现万物互联离不开低延时技术的应用。 LiveVideoStackCon 2023 深圳站邀请到秒点科技的CEO扶凯&#xff0c;为大家分享低延时技术在物联网、…

家政行业的小程序都需要具备哪些功能?

家政服务小程序&#xff0c;覆盖多城&#xff0c;在线派单 适合行业&#xff1a;家电维修、家政保洁、养生护理、美容美发、预约服务上门等 系统功能&#xff1a;服务管理、商品管理、拼团/秒杀、订单管理、会员管理、派单管理、师傅管理、商家/服务点、财务管理、城市代理、次…

Python算法例30 统计前面比自己小的数

1. 问题描述 给定一个整数数组&#xff08;数组大小为n&#xff0c;元素的取值范围为0~10000&#xff09;&#xff0c;对于数组中的每个元素&#xff0c;计算其前面元素中比它小的元素数量。 2. 问题示例 对于数组[1&#xff0c;2&#xff0c;7&#xff0c;8&#xff0c;5]&…

分享44个PyQt5源码总有一个是你想要的

分享44个PyQt5源码总有一个是你想要的 学习知识费力气&#xff0c;收集整理更不易。 知识付费甚欢喜&#xff0c;为咱码农谋福利。 链接&#xff1a;https://pan.baidu.com/s/1_5H_0Ydg0XUa1fz5Jok51Q?pwd6666 提取码&#xff1a;6666 项目名称 B站直播弹幕姬&#xff…

快速、安全、高效地传输海量小文件

随着互联网技术的不断进步&#xff0c;我们正迈入信息爆炸的时代。在这个时代&#xff0c;企业每天都需要在互联网上传输海量的小文件。与传输常见的大文件相比&#xff0c;海量小文件的传输变得更加困难。接下来&#xff0c;我们将分析海量小文件传输面临的挑战&#xff0c;并…