HarmonyOS第一课_构建更加丰富的页面
管理组件状态
概述
组件内的状态管理:@State
从父组件单向同步状态:@Prop
与父组件双向同步状态:@Link
跨组件层级双向同步状态:@Provide 和@Consume

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

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

在组件内使用@State 装饰器来修饰变量,可以使组件根据不同的状态来呈现不同的效果。若当前组件的状态需要通过其父组件传递而来,此时需要使用@Prop 装饰器;若是父子组件状态需要相互绑定进行双向同步,则需要使用@Link 装饰器。使用@Provide 和@Consume 装饰器可以实现跨组件层级双向同步状态。
在实际应用开发中,应用会根据需要封装数据模型。如果需要观察嵌套类对象属性变化,需要使用@Observed 和@ObjectLink 装饰器。
在实际应用开发中,应用会根据需要封装数据模型。如果需要观察嵌套类对象属性变化,需要使用@Observed 和@ObjectLink 装饰器。
父组件 TargetList 中内的状态管理:@State
实际开发中由于交互,组件的内容呈现可能产生变化。当需要在组件内使用状态来控制 UI 的不同呈现方式时,可以使用@State 装饰器。以任务管理应用为例,当点击子目标列表的其中一项,列表项会展开。当再次点击同一项,列表项会收起。所以,对于某一个列表项来说,它的呈现方式会受列表项是否展开这个状态影响。

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

//声明isExpanded变量
@State isExpanded: boolean = false;
...
if (this.isEditMode) {
Text($r('app.string.cancel_button'))
.onClick(() => {//点击取消按钮触发
this.isEditMode = false;
})
Text($r('app.string.select_all_button'))
} else {//点击编辑按钮触发
Text($r('app.string.edit_button'))
.onClick(() => {
this.isEditMode = true;
})
}
此时,需要使用@State 装饰器修饰 isExpanded,使其成为目标项内部的状态变量。通过@State 装饰后,框架内部会建立数据与视图间的绑定,

其具体实现只要用@State 修饰 isExpanded 变量,定义是否展开状态。然后通过条件渲染,实现是否显示进度调整面板和列表项的高度变化。最后,监听列表项的点击事件,在 onClick 回调中改变 isExpanded 状态。
这样就实现了对相同列表项点击时,列表项的展开和收起功能。当用户反复点击同一个列表项时,组件内的 isExpanded 状态变化,列表项会自动更新。
从父组件单向同步状态到子组件 TargetListItem:@Prop
当子组件中的状态依赖从父组件传递而来时,需要使用@Prop 装饰器,@Prop 修饰的变量可以和其父组件中的状态建立单向同步关系。当父组件中状态变化时,该状态值也会更新至@Prop 修饰的变量;对@Prop 修饰的变量的修改不会影响其父组件中的状态。

在目标管理应用中,当用户点击子目标列表的“编辑”文本,列表进入编辑模式,点击取消,列表退出编辑模式。
整个列表是自定义组件 TargetList,顶部是文本显示区域,主要是 Text 组件,底部是一个 Button 组件。中间区域则是用来显示每个目标项,目标项是自定义组件 TargetListItem。

从图中可以看出,TargetListItem 是 TargetList 的子组件。TargetList 是 TargetListItem 父组件。
对于父组件 TargetList,其顶部显示的文本和底部按钮会随编辑模式的变化而变化,因此父组件拥有编辑模式状态。
对于子组件 TargetListItem,其最右侧是否预留位置和显示勾选框也会随编辑模式变化,因此子组件也拥有编辑模式状态。
但是是否进入编辑模式,其触发点是在用户点击列表的“编辑”或取消按钮,状态变化的源头仅在于父组件 TargetList。当父组件 TargetList 中的编辑模式变化时,子组件 TargetListItem 的编辑模式状态需要随之变化。

在父组件 TargetList 中可以定义一个是否进入编辑模式的状态,即用@State 修饰 isEditMode。@State 修饰的变量不仅是组件内部的状态,也可以作为子组件单向或双向同步的数据源。ArkUI 提供了@Prop 装饰器,@Prop 修饰的变量可以和其父组件中的状态建立单向同步关系,所以用@Prop 修饰子组件 TargetListItem 中的 isEditMode 变量。
在父组件 TargetList 中,用@State 修饰 isEditMode,定义编辑模式状态。然后利用条件渲染实现根据是否进入编辑模式,显示不同的文本和按钮。同时,在父组件中需要在用户点击时改变状态,触发界面更新。
@Component
export default struct TargetListItem {
@Prop isEditMode: boolean;//从父组件TargetList传递过来的参数
...
Column() {
...
}
.padding({
...
right: this.isEditMode ? $r('app.float.list_edit_padding')
: $r('app.float.list_padding')//三元运算符,根据isEditMode的值选择排列的图标状态
})
...
if (this.isEditMode) {//根据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 变量的必须是在父组件中定义的状态变量。

在目标管理应用中,当用户点击同一个目标,目标项会展开或者收起。当用户点击不同的目标项时,除了被点击的目标项展开,同时前一次被点击的目标项会收起。
如上图所示,当目标一展开时,点击目标三,目标三会展开,同时目标一会收起。再点击目标一时,目标一展开,同时目标三会收起。
从目标一切换到目标三的流程中,关键在于最后目标一的收起,当点击目标三时,目标一需要知道点击了目标三,目标一才会收起。
在子目标列表中,每个列表项都有其位置索引值 index 属性,表示目标项在列表中的位置。index 从 0 开始,即第一个目标项的索引值为 0,第二个目标项的索引值为 1,以此类推。此外,clickIndex 用来记录被点击的目标项索引。当点击目标一时,clickIndex 为 0,点击目标三时,clickIndex 为 2。
在父组件子目标列表和每个子组件目标项中都拥有 clickIndex 状态。当目标一展开时,clickIndex 为 0。此时点击目标三,目标三的 clickIndex 变为 2,只要其父组件子目标列表感知到 clickIndex 状态变化,同时将此变化传递给目标一。目标一的 clickIndex 即可同步改变为 2,即目标一感知到此时点击了目标三。
将列表和目标项对应到列表组件 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
跨组件层级双向同步状态是指@Provide 修饰的状态变量自动对提供者组件的所有后代组件可用,后代组件通过使用@Consume 装饰的变量来获得对提供的状态变量的访问。@Provide 作为数据的提供方,可以更新其子孙节点的数据,并触发页面渲染。@Consume 在感知到@Provide 数据的更新后,会触发当前自定义组件的重新渲染。

使用@Provide 的好处是开发者不需要多次将变量在组件间传递。@Provide 和@Consume 的具体使用方法请参见开发指南:@Provide 装饰器和@Consume 装饰器:与后代组件双向同步。
HarmonyOS第一课_构建更加丰富的页面的更多相关文章
- 160921、React入门教程第一课--从零开始构建项目
工欲善其事必先利其器,现在的node环境下,有太多好用的工具能够帮助我们更好的开发和维护管理项目. 我本人不建议什么功能都自己写,我比较喜欢代码复用.只要能找到npm包来实现的功能,坚决不自己敲代码. ...
- jqueryMobile应用第一课《构建跨平台APP:jQuery Mobile移动应用实战》连载一(Hello World)
有人说每个程序员都曾经有过改变世界的梦想,笔者认为,这与程序员年轻时编写的第一个程序有着莫大的关系.简简单单的一句“hello world”让年轻的心开始相信梦想,用一种低调的壮志凌云向世界展示自己的 ...
- ChartControl第一课简短的控件初步设计
WinForms Controls >Controls > Chart Control > Getting Started This document gives you a qui ...
- Magento学习第一课——目录结构介绍
Magento学习第一课--目录结构介绍 一.Magento为何强大 Magento是在Zend框架基础上建立起来的,这点保证了代码的安全性及稳定性.选择Zend的原因有很多,但是最基本的是因为zen ...
- Spark 3000门徒第一课随笔
昨晚听了王家林老师的Spark 3000门徒系列课程的第一课,把scala基础过了一遍,对ArrayBuffer有了新的认识: Array本身创建后不可修改ArrayBuffer可修改import s ...
- python学习第一课要点记录
写在要点之前的一段话,留给将来的自己:第一次参加编程的培训班,很兴奋很激动,之前都是自己在网上找免费的视频来看,然后跟着写一些课程中的代码,都是照着模子写,没有自己过多的思考.感觉这样学不好,除了多写 ...
- 【Web探索之旅】第二部分第一课:客户端语言
内容简介 1.第二部分第一课:客户端语言 2.第二部分第二课预告:服务器语言 第二部分:Web编程语言和工具 大家好.上一个部分我们学习了Web的一些基本概念: 什么是Web? Internet和We ...
- 【C语言探索之旅】 第三部分第一课:SDL开发游戏之安装SDL
内容简介 1.课程大纲 2.第三部分第一课: SDL开发游戏之安装SDL 3.第三部分第二课预告: SDL开发游戏之创建窗口和画布 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会 ...
- Python作业第一课
零基础开始学习,最近周边的同学们都在学习,我也来试试,嘿嘿,都写下来,下次不记得了还能来看看~~ Python作业第一课1)登陆,三次输入锁定,下次不允许登陆2)设计一个三级菜单,菜单内容可自行定义, ...
- Ng第一课:引言(Introduction)
Machine Learning(机器学习)是研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已有的知识结构使之不断改善自身的性能. 它是人工智能的核心,是使计算机具有智能的根本 ...
随机推荐
- Prism报错
Rules.Default..WithoutFastExpressionCompiler()报错 说没有找到容器 1.查看Prism.Wpf源码 获取DryIoc容器规则 2.证明项目中出现了另外一个 ...
- React请求机制优化思路
说起数据加载的机制,有一个绕不开的话题就是前端性能,很多电商门户的首页其实都会做一些垂直的定制优化,比如让请求在页面最早加载,或者在前一个页面就进行预加载等等.随着react18的发布,请求机制这一块 ...
- 《Kali渗透基础》08. 弱点扫描(二)
@ 目录 1:OpenVAS / GVM 1.1:介绍 1.2:安装 1.3:使用 2:Nessus 2.1:介绍 2.2:安装 2.3:使用 3:Nexpose 本系列侧重方法论,各工具只是实现目标 ...
- 如何通过API接口获取微店的商品详情
微店是一款电商平台,对于商家而言,了解商品详情数据是非常重要的.通过API接口获取微店的商品详情,可以让商家更加便捷地管理和分析商品数据.下面就让我们详细了解一下如何通过API获取微店的商品详情. 第 ...
- 程序员:你如何写可重复执行的SQL语句?
上图的意思: 百战百胜,屡试不爽. 故事 程序员小张: 刚毕业,参加工作1年左右,日常工作是CRUD 架构师老李: 多个大型项目经验,精通各种开发架构屠龙宝术: 小张注意到,在实际的项目开发场景中,很 ...
- Go代码包与引入:如何有效组织您的项目
本文深入探讨了Go语言中的代码包和包引入机制,从基础概念到高级应用一一剖析.文章详细讲解了如何创建.组织和管理代码包,以及包引入的多种使用场景和最佳实践.通过阅读本文,开发者将获得全面而深入的理解,进 ...
- 「atcoder - abc246h」01? Queries
link. 平时基本打不到 ex,这个 ex 还是比较 ez 的,但也有些需要注意的地方. 考虑 dp 规划前缀,设 \(f[i][0/1]\) 表示前缀 \([1, i]\) 否是选 \(i\) 的 ...
- xshell无法调用gdc
现象: <topprod:/u1/topprod/tiptop> exe2 p_zzExecute program:p_zz<topprod:/u1/topprod/tiptop&g ...
- 文心一言 VS 讯飞星火 VS chatgpt (109)-- 算法导论10.1 7题
七.用go语言,说明如何用两个队列实现一个栈,并分析相关栈操作的运行时间. 文心一言: 在Go语言中,我们可以用两个队列(queue1和queue2)实现一个栈.以下是实现代码: package ma ...
- Merge-Lrc 合并歌词的小工具
Merge-Lrc 背景 音乐区有群友希望各种乱七八糟的歌词(lrc 格式居多,里面甚至还有翻译)可以整理成单一的文件,或者一个仅翻译的歌词可以和原文的歌词合并.于是就开发了这款工具.地址:https ...