鸿蒙 ArkTS 实战:Morning Checklist 从状态建模到交互闭环完整解析
鸿蒙 ArkTS 实战:Morning Checklist 从状态建模到交互闭环完整解析
前言
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
Morning Checklist 是一个面向 家庭生活效率 的鸿蒙 ArkTS 小应用。把起床流程、天气穿搭、待办同步和桌面卡片预览放在同一屏,适合做每日出门前的节奏管理。 本文围绕项目中的 entry/src/main/ets/pages/Index.ets 展开,拆解它的 数据模型、@State 状态、业务方法、Builder 组件 和页面布局方式,帮助读者理解一个轻量鸿蒙应用如何从静态数据走向可交互页面。

图示说明:页面以卡片、列表、输入框、按钮和状态统计为主体,适合在 DevEco Studio 中作为 ArkTS 组件化练习项目。
一、项目定位与功能闭环
1.1 应用要解决的问题
Morning Checklist 的业务入口非常轻:用户打开页面后,先看到已有数据和统计信息,再通过输入框或按钮触发状态变化。它不是重后台项目,而是典型的 单页状态驱动应用。
| 维度 | 项目表现 | 技术落点 |
|---|---|---|
| 数据承载 | 使用接口描述业务对象 | interface |
| 页面状态 | 使用 @State 保存列表、输入和开关 | ArkTS 状态管理 |
| 交互动作 | 点击按钮后重建数组或修改字段 | 不直接突变旧数组 |
| 视觉组织 | 卡片、行组件、统计块 | Builder 复用 |
| 运行环境 | DevEco Studio + 鸿蒙 ArkTS | Stage 模型页面 |
1.2 本文阅读重点
- 先看数据模型,理解页面到底在管理什么。
- 再看状态变量,判断哪些字段会触发 UI 刷新。
- 接着看核心方法,梳理新增、切换、筛选、统计等动作。
- 最后看页面布局,把业务数据映射成用户能理解的界面。
核心观点:ArkTS 页面开发的关键不是把控件堆满,而是让数据结构、状态变化和 UI 呈现形成稳定闭环。
二、工程结构与入口文件
2.1 目录结构
本项目是标准鸿蒙工程,核心页面位于 entry/src/main/ets/pages/Index.ets。文章聚焦这个文件,因为它包含了主要模型、状态、方法和 UI。
Morning Checklist
├── AppScope
├── entry
│ └── src
│ └── main
│ ├── ets
│ │ └── pages
│ │ └── Index.ets
│ └── module.json5
├── hvigor
├── build-profile.json5
└── oh-package.json5
2.2 页面入口
ArkTS 页面通过 @Entry 和 @Component 标记入口组件,uild() 方法负责描述 UI 树。
@Entry
@Component
struct Index {
build() {
Scroll() {
Column() {
// 页面内容
}
}
}
}
2.3 技术栈表
| 技术点 | 用途 | 在项目中的角色 |
|---|---|---|
| ArkTS | 页面逻辑与类型声明 | 主开发语言 |
| ArkUI | 声明式组件 | 构建界面 |
| @State | 响应式状态 | 驱动刷新 |
| @Builder | 组件片段复用 | 降低重复布局 |
| Hvigor | 构建系统 | 工程构建 |
三、数据模型设计
3.1 模型清单
源码中出现的业务模型为:$ifaceList。这些接口用于约束列表数据结构,让 UI 渲染时能明确字段来源。
interface MorningStep {
id: number;
title?: string;
name?: string;
done?: boolean;
status?: string;
}
上面的代码展示了这类模型的常见形态:id 用于列表 key,名称字段用于展示,状态字段用于判断颜色、按钮文案和操作结果。
3.2 模型设计表
| 模型 | 主要价值 | 页面用途 |
|---|---|---|
| $primaryInterface | 承载核心业务条目 | 列表渲染、按钮操作 |
| 辅助模型 | 承载记录、提示或分类 | 详情展示、过滤统计 |
| 状态字段 | 表示完成、提醒、选中等状态 | 控制颜色和文案 |
3.3 为什么用 interface
ArkTS 中使用 interface 可以在编写对象数组时获得更强的结构约束,减少字段拼写错误。对于列表型应用,这一点尤其重要。
实践要点:如果页面中有多条同结构数据,应优先抽象成接口,再让 @State 数组保存该接口类型。
四、状态变量拆解
4.1 @State 清单
项目中的状态声明包括:$stateList。
@State items: MorningStep[] = [];
@State draftText: string = '';
@State selectedIndex: number = 0;
@State enabled: boolean = true;
实际源码会根据业务命名,例如列表、输入框、筛选条件、开关状态等。它们共同决定页面当前显示什么、按钮点击后更新什么。
4.2 状态分类
| 状态类型 | 示例 | 作用 |
|---|---|---|
| 列表状态 | $primaryState | 页面主体数据 |
| 输入状态 | draftName、keyword、nswer | 接收用户输入 |
| 选择状态 | selectedId、 ilter、cursor | 决定当前视图 |
| 开关状态 | ||
| eminder、shared、 | ||
| ecording | 控制功能启停 | |
| 统计状态 | correct、wrong、seconds | 形成即时反馈 |
4.3 状态更新原则
ArkTS 页面中,列表更新常采用重建数组的方式,这样更容易触发界面刷新。
private updateItem(id: number): void {
this.items = this.items.map((item: MorningStep) => {
if (item.id !== id) {
return item;
}
return {
...item,
done: !item.done
};
});
}
五、核心方法解析
5.1 方法清单
源码中的核心方法包括:$methodList。这些方法构成了应用的业务动作层。
| 方法类型 | 常见方法 | 说明 |
|---|---|---|
| 统计方法 | otal、count、verage | 从列表中派生数字 |
| 新增方法 | ddItem、ddTask | 从输入状态创建新对象 |
| 切换方法 | oggle、 inish、 | |
| ext | 修改完成、提醒、进度 | |
| 过滤方法 | isible、 iltered | 根据关键词或分类筛选 |
| 展示方法 | ||
| ow、card、sectionHeader | 组织 UI 片段 |
5.2 统计方法
很多轻量应用都需要顶部统计卡片。统计方法通常通过 ilter、
educe 或数组长度计算。
private countActive(): number {
return this.items.filter((item: MorningStep) => !item.done).length;
}
private totalValue(): number {
return this.items.reduce((sum: number, item: MorningStep) => sum + 1, 0);
}
5.3 新增方法
新增逻辑的关键是从输入框状态读取文本,做空值判断,再把新对象插入列表。
private addItem(): void {
const title = this.draftText.trim();
if (title.length === 0) {
return;
}
const id = this.items.reduce((maxId: number, item: MorningStep) => Math.max(maxId, item.id), 0) + 1;
const item: MorningStep = { id: id, title: title, done: false };
this.items = [item, ...this.items];
this.draftText = '';
}
5.4 切换方法
完成、提醒、收藏、订阅这类动作都可以通过 map 生成新数组。
private toggleItem(id: number): void {
this.items = this.items.map((item: MorningStep) => {
return item.id === id ? { ...item, done: !item.done } : item;
});
}
六、Builder 组件复用
6.1 Builder 清单
项目中的 Builder 组件包括:$builderList。
@Builder 适合承载重复出现的 UI 片段,比如统计卡、列表行、筛选按钮、章节标题等。
@Builder
private row(item: MorningStep) {
Row() {
Text(item.title ?? item.name ?? '未命名')
.fontSize(16)
.fontWeight(FontWeight.Medium)
}
.padding(12)
.backgroundColor('#FFFFFF')
.borderRadius(8)
}
6.2 复用价值
| Builder | 复用价值 | 适用位置 |
|---|---|---|
| 统计卡片 | 避免重复写数字和标签布局 | 顶部概览 |
| 列表行 | 统一条目样式 | 主列表 |
| 筛选按钮 | 保持选中态一致 | 分类切换 |
| 区块标题 | 统一标题和辅助信息 | 页面分组 |
6.3 组件边界
Builder 不需要承担复杂业务判断,它更适合做“给定数据,渲染界面”。业务变化仍然放在 private 方法中。
七、页面布局结构
7.1 Scroll + Column
这批项目大多采用 Scroll 包裹 Column 的布局方式,适合移动端纵向内容流。
Scroll() {
Column() {
// 头部区域
// 输入区域
// 列表区域
// 详情区域
}
.width('100%')
.padding(16)
}
.height('100%')
.width('100%')
7.2 页面分区
| 分区 | 作用 | 常用组件 |
|---|---|---|
| 头部 | 展示标题、说明、统计 | Text、Row、Column |
| 输入区 | 接收新增数据 | TextInput、Button |
| 操作区 | 筛选、切换、开关 | Button、Toggle |
| 列表区 | 展示业务条目 | ForEach、Builder 行 |
| 结果区 | 展示统计或详情 | Card 风格容器 |
7.3 ForEach 渲染
列表通常通过 ForEach 渲染,并使用 id 作为稳定 key。
ForEach(this.items, (item: MorningStep) => {
this.row(item)
}, (item: MorningStep) => item.id.toString())
稳定 key 能减少列表刷新时的错位,也更利于后续扩展动画或局部更新。
八、交互闭环设计
8.1 从输入到列表
新增动作通常经过以下路径:
- TextInput 的 onChange 更新草稿状态。
- Button 的 onClick 调用新增方法。
- 新增方法创建业务对象。
- 列表状态重建,页面自动刷新。
TextInput({ text: this.draftText })
.onChange((value: string) => {
this.draftText = value;
})
Button('添加')
.onClick(() => {
this.addItem();
})
8.2 从按钮到状态
切换类按钮不需要复杂表单,只要传入条目 id 即可。
Button('完成')
.onClick(() => {
this.toggleItem(item.id);
})
8.3 状态反馈
按钮文案、颜色、标签和统计数字都来自状态。这样用户的每次点击都能马上看到反馈。
关键点:页面反馈越直接,工具应用越容易形成“点一下就知道结果”的操作感。
九、视觉层与信息层
9.1 色彩表达
项目常用白色卡片承载内容,用主题色突出主按钮,再用绿色、橙色、红色表达安全、待处理、异常等状态。
| 状态 | 色彩倾向 | 用户理解 |
|---|---|---|
| 正常 | 绿色 | 已完成、可用、安全 |
| 待处理 | 橙色 | 需要关注 |
| 异常 | 红色 | 需要立即处理 |
| 中性 | 灰色 | 普通说明 |
9.2 文本层级
标题使用较大字号,列表项名称使用中等字号,说明文本使用小字号。这样的层级适合小屏阅读。
Text('页面标题')
.fontSize(30)
.fontWeight(FontWeight.Bold)
Text('辅助说明')
.fontSize(14)
.fontColor('#667085')
十、鸿蒙 ArkTS 开发要点
10.1 类型先行
先定义接口,再写状态数组,可以让页面开发更稳。
10.2 状态集中
当前项目把状态集中在 Index 组件内,适合轻量单页应用。随着功能增加,可以再拆分组件或引入持久化。
10.3 方法命名
源码中的 $primaryMethod 等方法名直观表达动作,有利于阅读和维护。
10.4 UI 与逻辑分离
Builder 负责渲染,private 方法负责业务动作,这种分工能让页面不至于变成一整块难读代码。
十一、运行与调试流程
11.1 使用 DevEco Studio 打开
# 使用 DevEco Studio 打开项目目录
# 同步 oh-package 依赖
# 选择模拟器或真机运行 entry 模块
11.2 命令行构建思路
hvigorw clean
hvigorw assembleHap
11.3 调试观察点
| 观察点 | 关注内容 |
|---|---|
| 页面是否进入 | @Entry 是否正常加载 |
| 列表是否刷新 | @State 数组是否重建 |
| 输入是否生效 | onChange 是否写回状态 |
| 按钮是否响应 | onClick 是否调用方法 |
| 样式是否稳定 | 卡片宽度、颜色、字号是否一致 |
十二、可维护性拆解
12.1 文件规模
当前 Index.ets 约 369 行,属于可阅读的单页规模。随着功能继续增加,可以把列表行、统计卡和输入区拆到独立组件。
12.2 数据扩展
如果要接入本地存储,可以先为 $primaryInterface 增加序列化字段,再在页面加载时恢复列表。
interface StoredRecord {
id: number;
payload: string;
updatedAt: number;
}
12.3 异常边界
输入为空时直接返回,是轻量应用常见处理方式。更复杂的产品可以加入 Toast 或错误提示。
十三、同类项目迁移思路
13.1 可复用结构
Morning Checklist 的结构可以迁移到很多轻量工具:
- 一组业务对象。
- 一组页面状态。
- 若干统计方法。
- 一个新增入口。
- 一个列表展示区。
13.2 抽象模板
interface ItemModel {
id: number;
title: string;
done: boolean;
}
@State items: ItemModel[] = [];
private addItem(title: string): void {
this.items = [{ id: Date.now(), title: title, done: false }, ...this.items];
}
13.3 适配范围
| 应用类型 | 可复用部分 |
|---|---|
| 清单工具 | 列表、完成状态、统计 |
| 记录工具 | 输入、历史、筛选 |
| 学习工具 | 进度、得分、卡片 |
| 家庭工具 | 提醒、状态、分组 |
十四、项目亮点总结
14.1 业务表达清晰
Morning Checklist 没有把逻辑藏在复杂框架里,而是直接用接口、状态和方法表达业务。
14.2 页面反馈及时
每个操作都会落到 @State,列表、统计和按钮状态随之变化。
14.3 结构适合继续扩展
当前结构可以自然扩展持久化、搜索、排序、通知和多页面跳转。
十五、总结
Morning Checklist 展示了鸿蒙 ArkTS 单页应用的典型写法:通过 $ifaceList 建模业务数据,通过 $stateList 保存页面状态,通过 $methodList 完成统计、筛选、新增和切换,再通过 $builderList 把重复 UI 片段组件化。它的价值不只是一个具体工具,而是一套可以迁移到其他轻量应用的工程组织方式。
对于正在学习鸿蒙 ArkTS 的开发者来说,这个项目适合重点观察三件事:数据模型如何约束页面、状态变化如何驱动 UI、Builder 如何让列表和卡片保持一致。掌握这三点后,就能快速搭建更多家庭、学习、办公类小工具。
如果这篇文章对你有帮助,欢迎点赞、收藏、关注,你的支持是我持续创作的动力!
相关资源:
更多推荐




所有评论(0)