鸿蒙 ArkTS 实战:自行车停车记录的状态驱动界面与业务逻辑
鸿蒙 ArkTS 实战:自行车停车记录的状态驱动界面与业务逻辑
前言
停车地点、车位编号、预计停车小时和停车记录,是一个使用 ArkTS 与 ArkUI 实现的鸿蒙单页工具。
本文从 entry/src/main/ets/pages/Index.ets 出发,结合真实代码说明状态字段、派生函数、输入控件、数组更新和结果展示。

页面输入改变后,结果立即刷新,是声明式状态管理最直观的表现。
业务规则独立于组件树,能够让界面结构和计算逻辑同时保持清晰。
一、项目定位
1.1 使用场景
自行车停车记录把日常场景中的记录、计算和状态判断集中到一个页面。
用户通过滑块、文本框或按钮修改参数,页面根据当前状态给出反馈。
1.2 功能闭环
-
读取默认状态。
-
修改业务参数。
-
执行计算或数组操作。
-
查看结果与状态文字。
1.3 当前边界
当前功能位于 Index 组件中。
@State 保存交互数据,成员函数处理规则,build 组织 UI。
文章只分析代码已经实现的功能。
1.4 分析维度
| 层次 | 关注内容 | 页面体现 |
|—|—|—|
| 数据 | 状态和接口 | 输入与记录 |
| 规则 | 函数和阈值 | 计算与判断 |
| 交互 | 控件和回调 | 状态变化 |
| 展示 | ArkUI 组件 | 结果与列表 |
二、入口组件
2.1 页面定义
interface ParkingItem {
id: number
place: string
slot: string
hours: number
}
@Entry
@Entry 标识页面入口。
@Component 声明可渲染组件。
Index 集中承载状态、方法与 build。
2.2 状态入口
@Component
struct Index {
@State placeText: string = '地铁站B口'
@State slotText: string = 'A-12'
@State hoursText: string = '3'
@State records: ParkingItem[] = [
{ id: 1, place: '地铁站B口', slot: 'A-12', hours: 3 }
]
页面初始值决定首次打开时的结果。
数值落在控件范围内,数组数据用于展示列表初始状态。
2.3 构建函数
parseHours(): number {
const value = Number.parseFloat(this.hoursText)
return Number.isFinite(value) ? value : 1
}
addRecord(): void {
if (this.placeText.trim().length === 0 || this.slotText.trim().length === 0) { return }
build 使用 Column、Row、Text、Slider、TextInput、Button、Scroll 和 ForEach 组织页面。
2.4 布局顺序
结果区位于输入区之前。
用户打开页面就能看到当前状态,再向下调整参数。
三、状态字段
3.1 字段清单
| 状态字段 | 页面含义 | 业务作用 |
|—|—|—|
| placeText | 页面状态 | 参与自行车停车记录 |
| slotText | 页面状态 | 参与自行车停车记录 |
| hoursText | 页面状态 | 参与自行车停车记录 |
| records | 页面状态 | 参与自行车停车记录 |
这些字段同时连接控件、函数与展示区域。
3.2 状态职责
placeText、slotText、hoursText、records 分别承担输入、模式、记录集合或过程状态。
字段名称使用业务语义,阅读代码时容易定位。
3.3 响应式更新
@State 改变后,读取该字段的组件会重新计算。
页面不需要手动刷新 Text 节点。
3.4 初始状态代码
const nextId = this.records.length === 0 ? 1 : this.records[this.records.length - 1].id + 1
this.records = [{ id: nextId, place: this.placeText.trim(), slot: this.slotText.trim(), hours: this.parseHours() }, ...this.records]
this.slotText = ''
}
removeRecord(id: number): void {
this.records = this.records.filter((item: ParkingItem) => item.id !== id)
}
初始状态不仅提供示例,也用于验证布局和公式。
四、核心规则
4.1 规则说明
预计小时通过 parseFloat 转换,失败时使用 1;地点或车位为空时不新增;取车操作按 id 移除记录。
4.2 函数分工
项目中的关键函数包括:parseHours、addRecord、removeRecord。
这些函数分别处理转换、计算、状态映射或数组更新。
4.3 真实实现
build() {
Column() {
Column() {
Text('自行车停车记录').fontSize(28).fontWeight(FontWeight.Bold)
Text('记下停车位置,取车时不用凭记忆找车').fontSize(14).fontColor('#475569').margin({ top: 6 })
}.width('100%').padding(20).backgroundColor('#E0F2FE')
Scroll() {
函数直接读取当前状态,并把结果返回给 UI。
4.4 第二段规则
Column({ space: 14 }) {
Column() {
Text('新增停车记录').fontSize(18).fontWeight(FontWeight.Bold)
TextInput({ text: this.placeText, placeholder: '停车地点' }).margin({ top: 10 }).onChange((v: string) => { this.placeText = v })
Row({ space: 10 }) {
TextInput({ text: this.slotText, placeholder: '车位编号' }).layoutWeight(1).onChange((v: string) => { this.slotText = v })
TextInput({ text: this.hoursText, placeholder: '预计小时' }).layoutWeight(1).onChange((v: string) => { this.hoursText = v })
}.margin({ top: 10 })
复杂判断被留在成员函数中,build 只负责调用和展示。
五、边界处理
5.1 数字输入
文本数字进入业务逻辑前通过 parseInt 或 parseFloat 转换。
转换失败时使用兜底值或阻止操作。
5.2 范围保护
数量、剩余值和进度不应出现非法负数。
比例和阈值通过 Math.max、Math.min 或条件分支保护。
5.3 空值保护
名称写入数组前使用 trim。
空名称和无效数字不会创建记录。
5.4 边界代码
Button('保存位置').width('100%').margin({ top: 12 }).backgroundColor('#0284C7').onClick(() => { this.addRecord() })
}.padding(18).backgroundColor('#FFFFFF').borderRadius(10)
ForEach(this.records, (item: ParkingItem) => {
Row() {
Column() {
Text(item.place).fontSize(18).fontWeight(FontWeight.Bold)
Text('车位 ' + item.slot + ' · 预计 ' + item.hours.toFixed(1) + ' 小时').fontSize(13).fontColor('#64748B').margin({ top: 4 })
}.layoutWeight(1)
这段真实代码体现了当前页面对输入或结果范围的处理。
六、控件设计
6.1 Slider
Slider 处理时间、数量、重量、尺寸、里程或等级。
min、max 和 step 将输入限制在业务区间。
6.2 TextInput
TextInput 保存名称或数字文本。
onChange 只负责写回状态,转换工作交给业务函数。
6.3 Button
Button 用于新增、切换、消耗、完成或重新生成。
按钮文案和颜色可以从状态派生。
6.4 控件代码
Button('取车').backgroundColor('#DBEAFE').fontColor('#1D4ED8').onClick(() => { this.removeRecord(item.id) })
}.padding(16).backgroundColor('#FFFFFF').borderRadius(10)
}, (item: ParkingItem) => item.id.toString())
}.padding(18)
}.scrollBar(BarState.Off)
}.width('100%').height('100%').backgroundColor('#F0F9FF')
}
}
控件回调更新 @State 后,结果和状态文字同步变化。
七、数组与列表
7.1 记录结构
库存、事务和座位页面通过接口描述记录。
稳定的 id 用于定位和 ForEach key。
7.2 新增记录
新记录通常插入数组首位,让最新内容优先显示。
新增前会检查名称和数字。
7.3 更新记录
map 适合修改单条记录的数量、完成状态或占用状态。
filter 适合移除已经耗尽的记录。
7.4 二维数组
教室座位页面使用 SeatItem[][]。
外层数组代表行,内层数组代表每行座位。
八、布局分析
8.1 顶部结果
核心数字使用更大字号。
状态文案提供自然语言解释。
8.2 输入区域
参数控件集中在白色内容区域中。
统一内边距让标签与控件保持清晰关系。
8.3 状态颜色
| 状态 | 视觉表达 | 页面含义 |
|—|—|—|
| 正常或充足 | 绿色、青色 | 当前无需处理 |
| 中间状态 | 灰色、黄色 | 继续关注 |
| 临期、补货或超限 | 红色、深色 | 需要及时行动 |
8.4 滚动内容
Scroll 承载增长中的记录和网格。
滚动条可以隐藏,但纵向浏览能力保留。
九、交互流程
9.1 项目操作
填写地点、车位和预计时间后保存;取车时点击对应按钮,记录从列表中移除。
9.2 状态闭环
-
用户改变参数。
-
回调写回 @State。
-
派生函数重新执行。
-
结果文字和统计刷新。
-
数组型页面重新渲染列表。
9.3 操作反馈
| 操作 | 状态变化 | 页面反馈 |
|—|—|—|
| 拖动滑块 | 数值更新 | 结果变化 |
| 输入文本 | 文本更新 | 可提交内容变化 |
| 点击切换 | 布尔值或索引变化 | 文案和颜色变化 |
| 操作记录 | 数组元素变化 | 列表与统计变化 |
9.4 事件职责
回调保持短小。
业务判断放在具名函数中。
build 因此继续保持声明式结构。
十、ArkUI 组件职责
10.1 Text
Text 展示标题、单位、数值和状态。
字体层级区分主结果与辅助信息。
10.2 Row 与 Column
Column 负责纵向分区。
Row 负责并排展示统计和按钮。
layoutWeight 分配剩余宽度。
10.3 ForEach
ForEach 读取数组并生成记录项。
稳定 key 有利于列表更新。
10.4 Scroll
Scroll 让列表在移动端保持可浏览。
固定输入区和可增长列表形成清晰结构。
十一、声明式更新
11.1 单一数据来源
输入只保存在 @State。
结果由函数派生。
UI 不重复维护同一份计算结果。
11.2 计算与展示
预计小时通过 parseFloat 转换,失败时使用 1;地点或车位为空时不新增;取车操作按 id 移除记录。
公式位于函数中,Text 只读取返回值。
11.3 数组更新
数组重新赋值后,ForEach 读取最新集合。
统计函数也基于同一数组重新计算。
11.4 状态文案
状态函数把数字转换成临期、充足、需要保养、马上休息或已完成等文字。
这比只展示一个数值更容易理解。
十二、运行表现
12.1 首次打开
默认值立即生成结果。
用户无需先提交一次操作。
12.2 参数变化
滑块和按钮触发回调。
多个读取同一状态的区域同时刷新。
12.3 列表变化
新增、map 更新和 filter 移除形成完整记录链路。
顶部统计始终对应当前数组。
12.4 当前范围
当前代码聚焦单页交互和内存状态。
重新启动后的持久化、远程同步和多人协作不属于已实现范围。
十三、实现总结
自行车停车记录展示了鸿蒙 ArkTS 工具页面的典型组织方式:
-
@State 保存输入和记录。
-
成员函数承载规则和状态判断。
-
Slider、TextInput 与 Button 修改状态。
-
ForEach、map 和 filter 管理列表。
-
Text、Row、Column、Scroll 组织界面。
停车地点、车位编号、预计停车小时和停车记录这一场景通过明确的状态边界形成完整交互。
数据、规则、控件和反馈保持单向关系后,页面既容易操作,也容易阅读。
相关资源:
更多推荐




所有评论(0)