HarmonyOS开发(状态管理,页面路由,动画)

server/2024/10/24 10:18:54/
官网 https://developer.huawei.com/consumer/cn/

一、状态管理

在声明式UI中,是以状态驱动视图更新

1.@State

状态(State):指驱动视图更新的数据,被装饰器标记的变量

视图(View):基于UI描述渲染得到用户界面

说明

@State装饰器标记的变量必须初始化,不能为空值。

@State支持Object,class,string,number,boolean,enum类型以及这些类型的数组。

嵌套类型以及数组中的对象属性无法触发视图更新。

class Person{name:stringage:numbergf?:Personconstructor(name:string,age:number,gf?:Person) {this.name=name;this.age=age;this.gf=gf;}
}
@Entry
@Component
struct Index {@State idx:number=1@State name:string='Jack'@State age:number=10@State p:Person=new Person('Tony',20)@State p1:Person=new Person('Tom',20,new Person('Lily',18))@State gfs:Person[]=[new Person('露西',18),new Person('安娜',19)]build() {Column(){Text(`${this.name}${this.age}`).fontSize(40).onClick(()=>{this.age++})Text(`${this.p.name}${this.p.age}`).fontSize(40).onClick(()=>{this.p.age++})if (this.p1.gf)Text(`${this.p1.gf.name}${this.p1.gf.age}`).fontSize(40).onClick(()=>{//嵌套对象,对象内的属性发生变更无法触发视图变更if (this.p1.gf) this.p1.gf.age++})ForEach(this.gfs,(item:Person,index:number)=>{Row(){Text(`${item.name}:${item.age}`).fontSize(40).onClick(()=>{//数组中的对象属性无法触发视图更新item.age++//添加删除重新赋值才会触发视图更新this.gfs[index]=new Person(item.name,item.age)})Button('删除').onClick(()=>{this.gfs.splice(index,1)})}.justifyContent(FlexAlign.SpaceBetween)})Button('添加女友').onClick(()=>{this.gfs.push(new Person('女友'+this.idx++,18))})}.width('100%').height('100%')}
}
2.@Props和@Link

当父子组件之间需要数据同步时,可以使用@Props和@Link装饰器

@Props@Link
同步类型单向同步双向同步
允许装饰的变量类型

1.@Props只支持string,number,boolean,enum类型

2.父组件对象类型,子组件是对象属性

3不可以是数组,any

1.父子类型一致string,number,boolean,enum,object,class,以及它们的数组

2.数组中的元素增删替换会引起更新

3.嵌套类型以及数组中的对象属性无法触发视图更新

初始化方式不允许子组件初始化父组件传递,禁止子组件初始化

@Component
struct TaskStatistics{@Prop totalTask:number@Prop finishTask:numberbuild() {Row(){Text('任务进度:').fontSize(30)Stack({ alignContent: Alignment.Center }) {Progress({ value: this.finishTask, total: this.totalTask, type: ProgressType.Ring }).width(100).height(100)Text(`${this.finishTask}/${this.totalTask}`).fontSize(30)}}.width('100%').height(200).borderRadius(10).backgroundColor('#fff').justifyContent(FlexAlign.SpaceAround)}
}@Component
struct TaskList{@Link stat:Station@State tasks:Task[]=[]build() {Column(){Row(){Button('新增任务').onClick(()=>{this.tasks.push(new Task())this.stat.totalTask=this.tasks.length}).width(160)}.margin({top:10})List({space:10}) {ForEach(this.tasks, (item: Task, index: number) => {ListItem(){Row() {Text(`${item.name}`).fontSize(20)// .finishedStyle()Checkbox().select(item.finish).onChange((val) => {item.finish = val;this.stat.finishTask = this.tasks.filter((item) => {return item.finish}).length})}.margin({ top: 10 }).width('100%').height(50).borderRadius(10).backgroundColor('#fff').justifyContent(FlexAlign.SpaceBetween)}.swipeAction({end:this.DeleteButton(index)})})}.layoutWeight(1)}}@Builder DeleteButton(index:number) {Button() {Image($r('app.media.ic_public_delete_filled')).width(40).height(40)}.width(40).height(40).type(ButtonType.Circle).onClick(()=>{this.tasks.splice(index,1)this.stat.totalTask=this.tasks.lengththis.stat.finishTask = this.tasks.filter((item) => {return item.finish}).length})}
}class Station{totalTask:number=0finishTask:number=0
}
class Task{static id:number=1name:string='任务'+Task.id++finish:boolean=false
}
@Extend(Text) function finishedStyle(){.decoration({type:TextDecorationType.LineThrough}).fontColor('#b1b2b1')
}
@Entry
@Component
struct Index {@State stat:Station=new Station()@State tasks:Task[]=[]build() {Column() {//任务进度卡片TaskStatistics({ totalTask: this.stat.totalTask, finishTask: this.stat.finishTask })// 任务列表TaskList({stat:$stat })}.width('100%').height('100%').backgroundColor('#f6f6f6').padding(20)}
}
3.@Provide和Consume

可以跨组件提供类似于@Props和@Link的双向同步


@Component
struct TaskStatistics{@Consume stat:Stationbuild() {Row(){Text('任务进度:').fontSize(30)Stack({ alignContent: Alignment.Center }) {Progress({ value: this.stat.finishTask, total: this.stat.totalTask, type: ProgressType.Ring }).width(100).height(100)Text(`${this.stat.finishTask}/${this.stat.totalTask}`).fontSize(30)}}.width('100%').height(200).borderRadius(10).backgroundColor('#fff').justifyContent(FlexAlign.SpaceAround)}
}@Component
struct TaskList{@Consume stat:Station@State tasks:Task[]=[]build() {Column(){Row(){Button('新增任务').onClick(()=>{this.tasks.push(new Task())this.stat.totalTask=this.tasks.length}).width(160)}.margin({top:10})List({space:10}) {ForEach(this.tasks, (item: Task, index: number) => {ListItem(){Row() {Text(`${item.name}`).fontSize(20)// .finishedStyle()Checkbox().select(item.finish).onChange((val) => {item.finish = val;this.stat.finishTask = this.tasks.filter((item) => {return item.finish}).length})}.margin({ top: 10 }).width('100%').height(50).borderRadius(10).backgroundColor('#fff').justifyContent(FlexAlign.SpaceBetween)}.swipeAction({end:this.DeleteButton(index)})})}.layoutWeight(1)}}@Builder DeleteButton(index:number) {Button() {Image($r('app.media.ic_public_delete_filled')).width(40).height(50)}.width(40).height(50).type(ButtonType.Circle).onClick(()=>{this.tasks.splice(index,1)this.stat.totalTask=this.tasks.lengththis.stat.finishTask = this.tasks.filter((item) => {return item.finish}).length})}
}class Station{totalTask:number=0finishTask:number=0
}
class Task{static id:number=1name:string='任务'+Task.id++finish:boolean=false
}
@Extend(Text) function finishedStyle(){.decoration({type:TextDecorationType.LineThrough}).fontColor('#b1b2b1')
}
@Entry
@Component
struct Index {@Provide stat:Station=new Station()@State tasks:Task[]=[]build() {Column() {//任务进度卡片TaskStatistics()// 任务列表TaskList()}.width('100%').height('100%').backgroundColor('#f6f6f6').padding(20)}
}
4.@Observed和@ObiectLink

@Observed和@ObiectLink装饰器用于在涉及嵌套对象或数组元素为对象的场景中进行双向数据同步

//任务进度卡片组件
@Component
struct TaskStatistics{@Consume stat:Stationbuild() {Row(){Text('任务进度:').fontSize(30)Stack({ alignContent: Alignment.Center }) {Progress({ value: this.stat.finishTask, total: this.stat.totalTask, type: ProgressType.Ring }).width(100).height(100)Text(`${this.stat.finishTask}/${this.stat.totalTask}`).fontSize(30)}}.width('100%').height(200).borderRadius(10).backgroundColor('#fff').justifyContent(FlexAlign.SpaceAround)}
}
// 任务列表项组件
@Component
struct TaskItem{@ObjectLink item:TaskonTaskChange:()=>void=()=>{}build() {Row() {if(this.item.finish) {Text(`${this.item.name}`).fontSize(20).finishedStyle()}else{Text(`${this.item.name}`).fontSize(20)}Checkbox().select(this.item.finish).onChange((val) => {this.item.finish = val;this.onTaskChange()})}.margin({ top: 10 }).width('100%').height(50).borderRadius(10).backgroundColor('#fff').justifyContent(FlexAlign.SpaceBetween)}
}
// 任务列表组件
@Component
struct TaskList{@Consume stat:Station@State tasks:Task[]=[]handleTaskChange(){this.stat.finishTask = this.tasks.filter((item) => {return item.finish}).lengththis.stat.totalTask=this.tasks.length}build() {Column(){Row(){Button('新增任务').onClick(()=>{this.tasks.push(new Task())this.handleTaskChange()}).width(160)}.margin({top:10})List({space:10}) {ForEach(this.tasks, (item: Task, index: number) => {ListItem(){TaskItem({ item: item, onTaskChange: this.handleTaskChange.bind(this) })}.swipeAction({end:this.DeleteButton(index)})})}.layoutWeight(1)}}@Builder DeleteButton(index:number) {Button() {Image($r('app.media.ic_public_delete_filled')).width(40).height(50)}.width(40).height(50).type(ButtonType.Circle).onClick(()=>{this.tasks.splice(index,1)this.handleTaskChange()})}
}class Station{totalTask:number=0finishTask:number=0
}
@Observed
class Task{static id:number=1name:string='任务'+Task.id++finish:boolean=false
}
@Extend(Text) function finishedStyle(){.decoration({type:TextDecorationType.LineThrough}).fontColor('#b1b2b1')
}
@Entry
@Component
struct Index {@Provide stat:Station=new Station()build() {Column() {//任务进度卡片TaskStatistics()// 任务列表TaskList()}.width('100%').height('100%').backgroundColor('#f6f6f6').padding(20)}
}

二、页面路由

页面路由是指在应用程序中实现不同页面之间的跳转和传递函数。

页面栈的最大容量上限为32 个页面,使用,router.clear()方法可以清空页面栈,释放内存。

1.Router有两种页面跳转模式

router.pushUrl()目标页不会替换当前页,而是压入栈,因此可以用router.back()返回当前页

router.replaceUrl目标页替换当前页,当前页面会被销毁并释放资源,无法返回当前页

2.Router有两种页面实例模式

standard标准实例模式,每一次跳转都会新建一个目标页压入栈顶,默认就是这种模式

single单实例模式,如果目标页已经在栈中,则离栈顶最近的url页面会被移动到栈顶并重新加载

3.使用步骤
//1.导入harmonyos提供的Router模块
import router from '@ohos.router';//利用router实现跳转、返回操作
router.pushUrl({url:'pages/ImagePage',params:{id:1}},router.RouterMode.Single,err=>{if(err){console.log(err)}}
}//获取传递过来的参数
params:any=router.getParams()
//返回上一页
router.back()
//返回到指定页,并携带参数
router.back({url:'pages/Index',params:{id:10}}
)
4.示例

import router from '@ohos.router';
class Router{url:stringtitle:stringconstructor(url:string,title:string) {this.url=url;this.title=title;}
}
@Entry
@Component
struct Index {@State message:string='页面列表'private routers:Router[]=[new Router('pages/ComIndex','图片页面'),new Router('pages/CustomIndex','自定义组件页面'),new Router('pages/ForEachIndex','渲染页面'),new Router('pages/ProvideIndex','任务列表页面')]build() {Column() {//标题Text('页面列表').fontSize(35)//列表List(){ForEach(this.routers,(router:Router,index)=>{ListItem(){this.RouterItem(router,index+1)}})}}.width('100%').height('100%').backgroundColor('#f6f6f6').padding(20)}@Builder RouterItem(r:Router,i:number){Row(){Text(i+'.').fontSize(30)Blank()Text(r.title).fontSize(30)}.width('100%').height(60).padding(10).margin({bottom:20}).backgroundColor('#36d').borderRadius(25).onClick(()=>{router.pushUrl({url:r.url,params:{idx:i}},router.RouterMode.Single,err=>{if(err){console.log(err.message)}})})}
}

//Header组件可以返回上一页
import router from '@ohos.router';
interface Params {idx?: number; // idx 是可选的,可能存在也可能不存在
}
@Component
export struct Header {private title:ResourceStr|string=''@State params: Params = router.getParams() as Params; // 强制类型转换为 Paramsbuild(){Row(){Image($r('app.media.left')).width(30).onClick(()=>{router.showAlertBeforeBackPage({message:'确定要返回吗?'})router.back()})if(this.params &&this.title) {Text(this.params.idx +'.'+this.title).fontSize(20).fontWeight(FontWeight.Bold)}Blank()Image($r('app.media.reset')).width(24).onClick(()=>{})}.width('100%').height(30).backgroundColor('#f6f6f6')}
}

三、动画

属性动画、显示动画、组件转场动画

1.属性动画

属性动画是通过设置组件的animation属性来给组件添加动画,当前组件的width,height,opacity,backgroundColor,scale,rotate,translate属性时,可以实现渐变过渡效果。

import router from '@ohos.router';
@Entry
@Component
struct FishIndex {@State fishX:number=200@State fishY:number=100@State isBegin:boolean=false@State angle:number=0@State src:Resource=$r('app.media.fish')build() {Row() {Button('返回').position({ x: 0, y: 0 }).onClick((event: ClickEvent) => {router.back()})if(!this.isBegin){Button('开始游戏').onClick(()=>{this.isBegin=true;})}else{Image(this.src).width(50).height(50).position({x:this.fishX,y:this.fishY}).rotate({angle:this.angle,centerX:'50%',centerY:'50%'}).animation({duration:500})Row(){Button('←').backgroundColor('#20101010').onClick((event: ClickEvent) => {this.fishX-=20this.src=$r('app.media.fish')})Column(){Button('↑').backgroundColor('#20101010').onClick((event: ClickEvent) => {this.fishY-=20})Button("↓").backgroundColor('#20101010').onClick((event: ClickEvent) => {this.fishY+=20})}Button('→').backgroundColor('#20101010').onClick((event: ClickEvent) => {this.src=$r('app.media.fish_rev')this.fishX+=20})}}}.width('100%').height('100%').backgroundImage($r('app.media.bg')).backgroundImageSize({ width: '100%', height: '100%' })}
}
2.显示动画

显示动画是通过全局animateTo函数来修改组件属性,实现属性变化时的渐变效果。

import router from '@ohos.router';
@Entry
@Component
struct FishIndex {@State fishX:number=200@State fishY:number=100@State isBegin:boolean=false@State angle:number=0@State src:Resource=$r('app.media.fish')build() {Row() {Button('返回').position({ x: 0, y: 0 }).onClick((event: ClickEvent) => {router.back()})if(!this.isBegin){Button('开始游戏').onClick(()=>{this.isBegin=true;})}else{Image(this.src).width(50).height(50).position({x:this.fishX,y:this.fishY}).rotate({angle:this.angle,centerX:'50%',centerY:'50%'})Row(){Button('←').backgroundColor('#20101010').onClick((event: ClickEvent) => {animateTo({duration:500},()=>{this.fishX-=20this.src=$r('app.media.fish')})})Column(){Button('↑').backgroundColor('#20101010').onClick((event: ClickEvent) => {animateTo({duration:500},()=>{this.fishY-=20})})Button("↓").backgroundColor('#20101010').onClick((event: ClickEvent) => {animateTo({duration:500},()=>{this.fishY+=20})})}Button('→').backgroundColor('#20101010').onClick((event: ClickEvent) => {animateTo({duration:500},()=>{this.src=$r('app.media.fish_rev')this.fishX+=20})})}}}.width('100%').height('100%').backgroundImage($r('app.media.bg')).backgroundImageSize({ width: '100%', height: '100%' })}
}
3.组件转场动画

组件的转场动画是在组件插入或移除时的过渡动画,通过组件的transition属性来配置

import router from '@ohos.router';
@Entry
@Component
struct FishIndex {@State fishX:number=200@State fishY:number=100@State isBegin:boolean=false@State angle:number=0@State src:Resource=$r('app.media.fish')build() {Row() {Button('返回').position({ x: 0, y: 0 }).onClick((event: ClickEvent) => {router.back()})if(!this.isBegin){Button('开始游戏').onClick(()=>{animateTo({duration:500},()=>{this.isBegin=true;})})}else{Image(this.src).width(50).height(50).position({x:this.fishX,y:this.fishY}).rotate({angle:this.angle,centerX:'50%',centerY:'50%'}).transition({type:TransitionType.Insert,opacity:0,translate:{x:-250}})}Row(){Button('←').backgroundColor('#20101010').onClick((event: ClickEvent) => {animateTo({duration:500},()=>{this.fishX-=20this.src=$r('app.media.fish')})})Column(){Button('↑').backgroundColor('#20101010').onClick((event: ClickEvent) => {animateTo({duration:500},()=>{this.fishY-=20})})Button("↓").backgroundColor('#20101010').onClick((event: ClickEvent) => {animateTo({duration:500},()=>{this.fishY+=20})})}Button('→').backgroundColor('#20101010').onClick((event: ClickEvent) => {animateTo({duration:500},()=>{this.src=$r('app.media.fish_rev')this.fishX+=20})})}}.width('100%').height('100%').backgroundImage($r('app.media.bg')).backgroundImageSize({ width: '100%', height: '100%' })}
}


http://www.ppmy.cn/server/134415.html

相关文章

实战 | 记一次实战中SelfXSS+CSRF+越权漏洞的组合拳

0x01 前言 在渗透测试中,经常能够遇到这样一种XSS漏洞,它通常存在于比较隐私的个人信息配置等等功能中,有一个非常鲜明的特点就是“只有自己可见,别人不可见”,XSS漏洞只能攻击自己自然是毫无价值的,因此此…

报表工具怎么选?山海鲸VS帆软,哪个更适合你?

概述 在国产报表软件市场中,山海鲸报表和帆软这两款工具都占有一席之地,许多企业在选择报表工具时常常在它们之间徘徊。然而,随着企业对数据分析需求的不断增长和复杂化,如何选取一款高效、易用且性价比高的报表工具,…

[deadlock]死锁导致的设备登录无响应问题

[deadlock]死锁导致的设备登录无响应问题 一、问题现象二、初步观察三、继续深挖查看netlink相关信息查看warnd进程栈 四、再接再厉查看warnd 用户栈 后记 一、问题现象 实验室一台压力测试设备突然无法登录,无论web页面,ssh或者telnet登录,…

跳表(Skip List)介绍

跳表(Skip List)介绍 跳表是一种用于有序数据的高效数据结构,结合了链表和分层结构的优点,主要用于快速查找、插入和删除操作。跳表由William Pugh在1989年提出,作为一种简单而有效的替代平衡树的数据结构&#xff0c…

oracle 数据库 迁移到 pgsql,防止出现重大bug 回滚到 oracle,需要同步数据如何处理?

oracle 数据库 迁移到 pgsql,防止出现重大bug 回滚到 oracle,需要同步数据如何处理? 用工具 , 出现大问题, 直接把pgsql 数据库同步到新的oracle 数据库

深入理解 WPF 数据绑定机制

一、引言 在现代软件开发中,创建具有良好用户体验的图形用户界面(GUI)至关重要。WPF 作为一种先进的 GUI 技术,提供了强大的数据绑定机制,使得开发人员能够轻松地将数据与用户界面元素进行关联,实现数据的…

Spark广播变量(类似小表广播)

广播变量: 举例:取前十的学生信息,处理学生分数信息得到前十学生的学号的数组,通过广播将这个变量广播出去 代码展示如下: import org.apache.spark.broadcast.Broadcast import org.apache.spark.rdd.RDD import o…

AUTOSAR_EXP_ARAComAPI的6章笔记(3)

☞返回总目录 相关总结:AutoSar AP CM实例说明符的使用方法的总结 6.3 在多绑定上下文中的使用 以下部分修改了在 6.2.1 中展示的示例,描述了如何在应用程序和实例清单中为单个 PPortPrototype 定义多个网络绑定,而无需更改自适应应用程序…