鸿蒙Next · ArkTS疫苗预约应用开发详解
鸿蒙Next · ArkTS疫苗预约应用开发详解
运行截图:



一、项目概述
随着移动互联网与智慧医疗的深度融合,在线疫苗预约已成为公共卫生服务数字化转型的重要组成部分。传统的疫苗接种流程通常需要用户线下排队、电话预约或通过第三方平台操作,流程繁琐且效率低下。为解决这一痛点,本项目基于 HarmonyOS Next 平台,使用 ArkTS 语言开发了一款疫苗预约应用,旨在为用户提供便捷、直观的在线预约体验。
本应用的核心功能包括:以列表形式展示可预约的疫苗信息,支持用户点选疫苗后在网格中选择合适的接种时间段,最终完成预约确认。整个交互流程简洁明了,从疫苗选择到时间预约再到确认提交,三步即可完成一次完整的预约操作。
本文将从项目架构、数据模型、UI组件实现、状态管理、交互逻辑等多个维度,对该应用进行全方位的技术解析,帮助开发者深入理解 ArkTS 声明式UI开发范式以及 HarmonyOS Next 应用开发的最佳实践。
二、技术架构与开发环境
2.1 技术栈
| 技术项 | 说明 |
|---|---|
| 开发平台 | HarmonyOS Next |
| 开发语言 | ArkTS(Ark TypeScript) |
| UI范式 | 声明式UI(ArkUI) |
| IDE | DevEco Studio |
| 目标设备 | 手机(phone) |
ArkTS 是 HarmonyOS Next 的主力开发语言,它在 TypeScript 的基础上扩展了声明式UI能力,使得开发者能够通过简洁的语法描述界面结构和状态变化。与传统的命令式UI开发不同,ArkTS 采用声明式范式:开发者只需描述"界面应该是什么样的",框架会自动处理视图的创建、更新和销毁。
2.2 项目结构
ArkTSVaccine/
├── AppScope/ # 应用级配置和资源
│ ├── app.json5 # 应用配置
│ └── resources/ # 应用级资源
├── entry/ # 主模块
│ └── src/main/
│ ├── ets/ # ArkTS源码
│ │ ├── entryability/ # 入口Ability
│ │ └── pages/
│ │ └── Index.ets # 主页面(核心代码)
│ ├── resources/ # 模块资源
│ │ ├── base/ # 基础资源
│ │ └── dark/ # 深色模式资源
│ └── module.json5 # 模块配置
└── build-profile.json5 # 构建配置
整个应用的核心逻辑集中在一个页面 Index.ets 中,采用单页面架构设计。这种设计对于功能相对聚焦的工具类应用来说非常合适,既降低了代码复杂度,又保证了用户体验的连贯性。
三、数据模型设计
3.1 疫苗信息模型
interface VaccineInfo {
id: number; // 疫苗唯一标识
name: string; // 疫苗名称
description: string; // 疫苗说明
manufacturer: string;// 生产厂家
dose: string; // 接种剂次
price: string; // 价格信息
available: boolean; // 是否可预约
}
VaccineInfo 接口定义了疫苗的完整信息结构。其中 id 字段用于唯一标识每种疫苗,作为后续选择逻辑的关联键;available 字段则控制疫苗是否可被选中——当疫苗库存不足或暂时缺货时,该字段为 false,用户点击时不会触发选择逻辑,同时界面上会显示橙色的"暂缺"标签进行提示。
3.2 时间段模型
interface TimeSlot {
id: number; // 时间段唯一标识
time: string; // 时间范围(如 "08:00-09:00")
available: boolean; // 该时段是否可预约
}
TimeSlot 接口用于描述可预约的时间段。与疫苗模型类似,available 字段控制时段的可选性。已满或不可用的时间段在界面上会以半透明灰色显示,且不可点击。
3.3 数据定义方式
在 ArkTS 的组件中,接口定义位于组件外部,数据则通过 private 属性在组件内部初始化。这种写法将数据结构与组件逻辑紧密关联,适用于单页面应用的快速开发:
private vaccines: VaccineInfo[] = [
{
id: 1,
name: '新冠灭活疫苗',
description: '用于预防新型冠状病毒感染,适用于3岁及以上人群,需接种2剂次。',
manufacturer: '国药集团',
dose: '2剂次',
price: '免费',
available: true
},
// ...更多疫苗数据
];
预置了 5 款常见疫苗和 12 个时间段数据,模拟了真实的预约场景。其中乙肝疫苗的 available 设置为 false,用于演示缺货状态的 UI 表现。
四、状态管理
4.1 状态变量
ArkTS 的声明式UI核心在于状态驱动视图更新。本应用定义了三个关键状态变量:
@State selectedVaccineId: number = -1; // 当前选中的疫苗ID
@State selectedTimeSlotId: number = -1; // 当前选中的时间段ID
@State showConfirm: boolean = false; // 是否显示预约成功弹窗
@State 装饰器是 ArkTS 状态管理的基础。当被 @State 装饰的变量发生变化时,框架会自动重新执行 build() 方法,触发 UI 的重新渲染。这意味着开发者无需手动操作 DOM 或调用 setState 之类的命令式方法——只需修改状态值,界面就会自动更新。
4.2 状态流转逻辑
整个应用的状态流转遵循清晰的线性流程:
- 初始状态:两个选择 ID 均为 -1,表示未做任何选择,时间区域不显示
- 选择疫苗:
selectedVaccineId更新为对应 ID,时间网格区域条件渲染出现 - 选择时间段:
selectedTimeSlotId更新为对应 ID,已选摘要和确认按钮出现 - 确认预约:
showConfirm变为true,弹窗覆盖层显示 - 关闭弹窗:所有状态重置为初始值
这种状态流转设计确保了用户操作的有序性——必须先选疫苗,再选时间,最后才能确认。每一步都有明确的视觉反馈,降低了误操作的可能性。
4.3 选择互斥与重置
当用户切换疫苗选择时,已选的时间段需要重置:
.onClick(() => {
if (vaccine.available) {
this.selectedVaccineId = vaccine.id;
this.selectedTimeSlotId = -1; // 重置时间段选择
}
})
这是一个重要的交互细节。不同疫苗的可预约时段可能不同,切换疫苗后保留之前的时间选择可能导致逻辑冲突,因此每次切换疫苗时主动清除时间选择是合理的做法。
五、UI组件实现详解
5.1 整体布局架构
应用的布局采用 Stack 作为根容器,包含两个层级:底层是页面主体内容(顶部标题栏 + 可滚动内容区),顶层是条件渲染的预约成功弹窗。
build() {
Stack() {
Column() {
// 顶部标题栏
Row() { ... }
// 可滚动内容区
Scroll() { ... }
}
// 预约成功弹窗(条件渲染)
if (this.showConfirm) {
Column() { ... }
}
}
}
Stack 组件允许子元素层叠放置,非常适合实现弹窗、浮层等覆盖型 UI。弹窗组件通过 if 条件渲染——当 showConfirm 为 true 时创建并显示,为 false 时销毁。这种条件渲染方式比显式的 visibility 控制更高效,因为组件在不需要时不会占用渲染资源。
5.2 顶部标题栏
Row() {
Text('疫苗预约')
.fontSize(24)
.fontWeight(FontWeight.Bold)
.fontColor('#FFFFFF')
}
.width('100%')
.height(56)
.backgroundColor('#4CAF50')
.justifyContent(FlexAlign.Center)
标题栏使用 Row 水平布局,内部仅包含一个居中的 Text 组件。#4CAF50 是一个柔和的绿色,既符合医疗健康类应用的视觉调性,又不会过于刺眼。整个标题栏固定高度 56vp,与系统标准标题栏高度保持一致。
5.3 疫苗列表(List 组件)
疫苗列表是本应用的核心展示组件之一,采用 List + ForEach 的组合实现动态列表渲染:
List({ space: 12 }) {
ForEach(this.vaccines, (vaccine: VaccineInfo) => {
ListItem() {
Row() {
Column() { /* 疫苗信息 */ }
.layoutWeight(1)
Stack() { /* 选中指示器 */ }
}
.padding(16)
.borderRadius(12)
.backgroundColor(...)
.border(...)
.shadow(...)
.onClick(() => { ... })
}
})
}
.width('100%')
.padding({ left: 16, right: 16 })
每个列表项是一个 Row 水平布局,左侧为疫苗详细信息(使用 Column 垂直排列),右侧为选中指示器(使用 Stack 叠加圆形和勾选图标)。
关键设计细节:
space: 12:列表项之间的间距为 12vp,配合卡片式设计营造清晰的视觉层次layoutWeight(1):让信息区域占据剩余空间,选择器固定在右侧- 条件边框与背景:选中状态的卡片变为浅绿色背景 + 绿色边框,未选中为白色背景 + 浅灰边框
- 阴影效果:
shadow属性为卡片添加微妙的投影,增强层次感 - 暂缺标签:当疫苗不可用时,在名称后显示橙色"暂缺"标签,使用内联
padding和borderRadius实现胶囊形状
选中指示器的实现
Stack() {
Circle()
.width(22)
.height(22)
.fill(this.selectedVaccineId === vaccine.id ? '#4CAF50' : 'transparent')
.stroke(this.selectedVaccineId === vaccine.id ? '#4CAF50' : '#CCCCCC')
.strokeWidth(this.selectedVaccineId === vaccine.id ? 0 : 2)
if (this.selectedVaccineId === vaccine.id) {
Text('✓')
.fontSize(14)
.fontColor('#FFFFFF')
}
}
.width(24)
.height(24)
选中指示器使用 Stack 叠加一个 Circle 和一个条件渲染的 Text(勾选符号)。未选中时显示灰色空心圆,选中时变为绿色实心圆并叠加白色勾号。Stack 的默认对齐方式为居中,因此勾号自然位于圆形中心,无需额外定位。
5.4 时间段网格(Grid 组件)
时间段选择区域使用 Grid 组件实现 3 列 4 行的网格布局:
Grid() {
ForEach(this.timeSlots, (slot: TimeSlot) => {
GridItem() {
Column() {
Text(slot.time.split('-')[0]) // 开始时间
Text(slot.time.split('-')[1]) // 结束时间
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.borderRadius(8)
.backgroundColor(...)
.border(...)
.opacity(!slot.available ? 0.5 : 1)
.onClick(() => { ... })
}
})
}
.columnsTemplate('1fr 1fr 1fr')
.rowsTemplate('1fr 1fr')
.columnsGap(10)
.rowsGap(10)
.width('100%')
.height(170)
Grid 布局要点:
columnsTemplate('1fr 1fr 1fr'):定义三列等宽网格rowsTemplate('1fr 1fr'):定义两行等高网格columnsGap(10)和rowsGap(10):网格间距为 10vp- 总高度固定 170vp,12 个时间段通过滚动展示
每个网格项展示两行文字——上方为开始时间(较大字号、较粗字体),下方为结束时间(较小字号、灰色)。不可用的时间段通过 opacity(0.5) 降低不透明度,直观地传达"不可选"状态。
5.5 预约成功弹窗
弹窗通过 Stack 覆盖层实现,包含半透明遮罩和居中白色卡片:
if (this.showConfirm) {
Column() {
// 遮罩层
Column()
.width('100%')
.height('100%')
.backgroundColor('rgba(0,0,0,0.5)')
.onClick(() => { this.showConfirm = false; })
// 弹窗卡片
Column() {
Text('✓') // 成功图标
Text('预约成功!') // 标题
Text(this.getVaccineName()) // 疫苗名称
Text(this.getTimeSlot()) // 时间段
Text('请按时到达接种点,携带有效身份证件。') // 提示
Button('确定') // 关闭按钮
}
.width(300)
.padding(30)
.borderRadius(16)
.backgroundColor('#FFFFFF')
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
遮罩层铺满全屏,点击可关闭弹窗。弹窗卡片固定宽度 300vp,圆角 16vp,通过 justifyContent(FlexAlign.Center) 在 Stack 中垂直居中。弹窗内容简洁明了:成功图标、预约摘要、温馨提示和确认按钮,层次分明。
5.6 Toast 提示
点击"确认预约"按钮时,通过 promptAction.showToast 弹出轻量级提示:
.onClick(() => {
promptAction.showToast({
message: '预约成功!疫苗:' + this.getVaccineName() + ',时间:' + this.getTimeSlot(),
duration: 2000
});
this.showConfirm = true;
})
Toast 提示会在屏幕底部短暂显示 2 秒后自动消失,为用户提供即时的操作反馈,同时不打断主流程。这种轻量级反馈与弹窗形成互补——Toast 做即时确认,弹窗做详细信息展示。
六、交互设计与用户体验
6.1 渐进式披露
应用采用了渐进式披露(Progressive Disclosure)的交互设计原则。初始状态下,页面仅展示疫苗列表。只有当用户选择了某个疫苗后,时间段网格才会出现;只有当用户同时选好了疫苗和时间,确认按钮和已选摘要才会展示。
这种设计减少了初始界面的信息密度,让用户可以专注于当前步骤,降低了认知负担。同时,逐步展开的内容也形成了一种引导式的操作流程,暗示用户按步骤完成预约。
6.2 视觉反馈体系
应用建立了一套完整的视觉反馈体系:
| 状态 | 反馈方式 |
|---|---|
| 可选 | 白色背景、灰色边框、正常不透明度 |
| 选中 | 绿色背景、绿色边框、勾选图标 |
| 不可用 | 灰色背景、低不透明度、禁止点击 |
| 暂缺 | 橙色标签、背景不可点击 |
绿色(#4CAF50)作为主色调贯穿整个应用,既代表"健康"和"通过"的心理暗示,又在视觉上形成统一的品牌感知。
6.3 辅助方法
为了保持模板代码的简洁,将数据查询逻辑封装为私有方法:
private getVaccineName(): string {
for (const vaccine of this.vaccines) {
if (vaccine.id === this.selectedVaccineId) {
return vaccine.name;
}
}
return '';
}
private getTimeSlot(): string {
for (const slot of this.timeSlots) {
if (slot.id === this.selectedTimeSlotId) {
return slot.time;
}
}
return '';
}
这两个方法在弹窗和摘要区域被多次调用,避免了在模板中编写重复的查找逻辑,提升了代码的可读性和可维护性。
七、关键ArkTS特性应用
7.1 条件渲染
应用大量使用了 if 条件渲染来控制组件的显示与隐藏:
// 时间区域在选择疫苗后出现
if (this.selectedVaccineId > 0) {
// 时间网格和相关UI
}
// 已选摘要在选择时间后出现
if (this.selectedTimeSlotId > 0) {
// 摘要和确认按钮
}
// 弹窗在确认时出现
if (this.showConfirm) {
// 弹窗组件
}
ArkTS 的条件渲染与传统的 v-if 或条件样式不同——当条件为 false 时,组件不仅不可见,而且不会被创建到渲染树中,从而节省了内存和渲染开销。
7.2 ForEach 列表渲染
ForEach(this.vaccines, (vaccine: VaccineInfo) => {
ListItem() { ... }
})
ForEach 是 ArkTS 中处理列表渲染的核心 API。它接收数据源和渲染函数,为每个数据项创建对应的组件实例。当数据源发生变化时,框架会自动进行差异对比并更新视图。
7.3 声明式属性绑定
ArkTS 的属性绑定语法使得样式可以动态响应状态变化:
.backgroundColor(this.selectedVaccineId === vaccine.id ? '#E8F5E9' : '#FFFFFF')
.border({
width: this.selectedVaccineId === vaccine.id ? 1.5 : 1,
color: this.selectedVaccineId === vaccine.id ? '#4CAF50' : '#EEEEEE'
})
这种写法将样式逻辑与状态直接绑定,无需手动操作样式类或属性,代码意图清晰明了。
八、总结与展望
本疫苗预约应用通过简洁的架构设计和声明式UI开发范式,在单页面内实现了完整的预约流程。核心技术亮点包括:使用 @State 实现响应式状态管理、List + ForEach 实现动态列表、Grid 实现时间段网格布局、Stack 实现弹窗覆盖层,以及条件渲染实现渐进式交互。
在实际生产环境中,该应用还可以进行以下方向的扩展:接入后端 API 实现真实数据交互、添加用户登录和身份认证、引入预约记录管理、支持多城市/多医院选择、集成日历组件提供更直观的日期选择、以及添加推送通知功能提醒用户按时接种。
ArkTS 的声明式UI开发范式大幅降低了移动端界面开发的门槛,使得开发者能够更加专注于业务逻辑和用户体验的设计,而非繁琐的视图操作。随着 HarmonyOS 生态的不断发展完善,ArkTS 在智慧医疗、公共服务等领域的应用前景将更加广阔。
更多推荐



所有评论(0)