ArkTS急救指南应用开发实战——鸿蒙原生HarmonyOS全流程详解

运行截图:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

前言

在日常生活中,突发意外情况时有发生,掌握基本的急救知识对于每个人来说都至关重要。烫伤、心肺复苏、止血等常见急救场景,普通人往往因缺乏系统性的指导而手忙脚乱。如果能有一款手机应用,在紧急时刻快速提供清晰、结构化的急救步骤指引,将极大提高自救互救的效率。

本文将详细介绍如何使用 ArkTS 语言,在 HarmonyOS(鸿蒙)平台上从零开始开发一款急救指南应用。该应用采用 Grid 网格布局展示急救场景分类(烫伤、心肺复苏、止血),使用 List 列表展示每个场景的详细操作步骤。文章将涵盖项目架构设计、数据模型定义、UI 组件实现、状态管理机制以及编译调试中遇到的实际问题与解决方案,适合对 ArkTS 和 HarmonyOS 开发感兴趣的开发者参考学习。

一、项目概述与技术选型

1.1 项目目标

本项目旨在构建一个轻量级的急救知识指南应用,核心功能包括:

  • 急救场景分类展示:通过 Grid 网格卡片,直观展示烫伤、心肺复苏、止血三大常见急救场景。
  • 详细步骤指引:点击任意场景卡片后,下方以 List 列表形式逐步展示该场景的完整急救操作流程。
  • 关键警告提示:在操作步骤中嵌入红色警告信息,提醒用户避免常见误区。
  • 交互状态反馈:选中的场景卡片带有高亮边框和背景色变化,未选择时显示引导提示。

1.2 技术选型

技术项 选择 说明
开发语言 ArkTS HarmonyOS 推荐的声明式 UI 开发语言
UI 框架 ArkUI 声明式范式 基于装饰器 + Builder 模式的组件化开发
布局组件 Grid + List Grid 用于分类选择,List 用于步骤详情展示
状态管理 @State 装饰器 组件内状态管理,驱动 UI 响应式更新
运行平台 HarmonyOS NEXT 鸿蒙原生应用平台

1.3 项目结构

ArkTSFirstAd/
├── AppScope/                    # 应用级配置
│   └── app.json5               # 应用描述文件
├── entry/                       # 主模块
│   └── src/main/
│       ├── ets/
│       │   ├── entryability/
│       │   │   └── EntryAbility.ets    # 应用入口 Ability
│       │   └── pages/
│       │       └── Index.ets           # 主页面(核心代码)
│       └── resources/                  # 资源文件
│           └── base/
│               ├── element/            # 颜色、字符串等基础元素
│               └── media/              # 图片等媒体资源
├── build-profile.json5          # 构建配置
└── oh-package.json5             # 包描述文件

整个应用的核心业务逻辑集中在 entry/src/main/ets/pages/Index.ets 这一个文件中,采用单页面架构实现全部功能,结构简洁明了。

二、数据模型设计

良好的数据模型是应用开发的基础。本项目定义了两个核心接口来描述急救指南的数据结构。

2.1 急救步骤接口 FirstAidStep

interface FirstAidStep {
  step: number        // 步骤序号
  title: string       // 步骤标题
  description: string // 步骤详细描述
  warning?: string    // 可选的警告提示信息
}

FirstAidStep 接口描述单个急救操作步骤。其中 warning 字段使用了 TypeScript 的可选属性语法(?),表示该字段不是必须的。只有在步骤中存在需要特别提醒的操作注意事项时,才会提供该字段值。

2.2 急救分类接口 FirstAidCategory

interface FirstAidCategory {
  id: number              // 分类唯一标识
  name: string            // 分类名称(烫伤/心肺复苏/止血)
  icon: string            // 分类图标(Emoji)
  color: string           // 主题颜色(Hex 色值)
  steps: FirstAidStep[]   // 该分类下的所有操作步骤
}

FirstAidCategory 接口定义了一个完整的急救场景分类。每个分类拥有独立的主题色、图标和一系列操作步骤。color 字段不仅用于分类卡片的视觉区分,还会贯穿到步骤编号圆圈、选中边框等全局视觉元素中,确保一致的设计语言。

2.3 急救数据定义

项目将所有急救知识以常量数组的形式内联定义在页面文件中,便于开发阶段的快速迭代:

const firstAidData: FirstAidCategory[] = [
  {
    id: 1,
    name: '烫伤',
    icon: '🔥',
    color: '#FF6B35',    // 橙色主题
    steps: [
      {
        step: 1,
        title: '脱离热源',
        description: '立即远离烫伤源,脱去或剪开覆盖伤口的衣物。',
        warning: '切勿强行撕扯粘在皮肤上的衣物'
      },
      // ... 共 5 个步骤
    ]
  },
  {
    id: 2,
    name: '心肺复苏',
    icon: '❤️',
    color: '#E63946',    // 红色主题
    steps: [
      // ... 共 6 个步骤
    ]
  },
  {
    id: 3,
    name: '止血',
    icon: '🩸',
    color: '#A4133C',    // 深红色主题
    steps: [
      // ... 共 6 个步骤
    ]
  }
]

三个分类采用不同的暖色系主题色,既区分了场景,又在视觉上保持了急救主题的统一感。烫伤使用橙色(#FF6B35)传递温暖感,心肺复苏使用标准红色(#E63946)呼应心脏主题,止血使用深红色(#A4133C)暗示血液颜色。

三、页面整体布局架构

3.1 页面结构分析

整个页面从上到下采用 Column 垂直布局,分为四个核心区域:

┌─────────────────────────┐
│    顶部标题栏 (Row)      │  高度固定 56vp,红色背景
├─────────────────────────┤
│    Grid 分类选择区域      │  白色背景,高度 100vp
├─────────────────────────┤
│    分隔线 (Divider)      │  stroke 高度 8vp
├─────────────────────────┤
│                         │
│    List 步骤详情区域      │  占满剩余空间
│    (或空状态提示)         │
│                         │
└─────────────────────────┘

3.2 根容器与主构建方法

@Entry
@Component
struct Index {
  @State selectedId: number = -1
  @State categories: FirstAidCategory[] = firstAidData

  build() {
    Column() {
      // 顶部标题栏
      // Grid 分类区域
      // 分隔线
      // 详情步骤列表(条件渲染)
    }
    .width('100%')
    .height('100%')
  }
}

@Entry 装饰器标记该组件为页面入口组件。@Component 装饰器表明这是一个可复用的 UI 组件。struct Index 是组件的声明,采用值类型(struct)而非引用类型(class),这是 ArkTS 组件声明的标准写法。

四、状态管理机制详解

4.1 @State 装饰器

本应用使用了两个 @State 状态变量来驱动 UI 更新:

@State selectedId: number = -1       // 当前选中的分类 ID,-1 表示未选中
@State categories: FirstAidCategory[] = firstAidData  // 急救分类数据

@State 是 ArkUI 框架中最基础的状态管理装饰器。当被 @State 标注的变量发生变化时,框架会自动检测依赖该变量的 UI 组件并触发重新渲染。在本应用中:

  • selectedId:核心交互状态。当用户点击 Grid 中的分类卡片时,selectedId 会被更新为对应分类的 id,从而触发 build() 方法重新执行,下方的 List 区域根据条件渲染逻辑展示对应步骤。
  • categories:数据源状态。在当前实现中数据为静态常量,但保留为 @State 便于未来扩展为动态加载场景。

4.2 条件渲染逻辑

if (this.selectedId === -1) {
  // 显示空状态提示
  Column() {
    Text('👆')
    Text('请在上方选择急救场景')
    Text('查看详细操作步骤')
  }
} else {
  this.DetailListBuilder()
}

这段条件渲染逻辑实现了两个视图的切换:未选择时展示引导提示,选择后展示步骤详情。ArkTS 的声明式语法中 if-else 可以直接在 build() 方法中使用,框架会根据条件自动管理 DOM 节点的创建和销毁。

五、Grid 分类网格实现

5.1 Grid 组件配置

Grid() {
  ForEach(this.categories, (item: FirstAidCategory) => {
    GridItem() {
      this.GridItemBuilder(item)
    }
    .aspectRatio(1)
  })
}
.columnsTemplate('1fr 1fr 1fr')    // 3 列等宽
.rowsTemplate('1fr')                // 1 行
.columnsGap(12)                     // 列间距 12vp
.width('100%')
.height(100)                        // 总高度 100vp

Grid 是 ArkUI 提供的网格布局组件,适合展示固定行列结构的卡片内容。.columnsTemplate('1fr 1fr 1fr') 将可用宽度三等分,每列占据相同比例的空间。.columnsGap(12) 在列与列之间添加 12vp 的间距。.aspectRatio(1) 确保每个 GridItem 为正方形,形成规整的卡片网格。

5.2 GridItemBuilder 构建器

@Builder
GridItemBuilder(item: FirstAidCategory) {
  Column() {
    Text(item.icon)
      .fontSize(36)

    Text(item.name)
      .fontSize(16)
      .fontWeight(FontWeight.Medium)
      .fontColor('#333333')
      .margin({ top: 8 })
  }
  .width('100%')
  .height('100%')
  .justifyContent(FlexAlign.Center)
  .backgroundColor(this.selectedId === item.id ? item.color + '18' : '#F7F8FA')
  .borderRadius(12)
  .border({
    width: this.selectedId === item.id ? 2 : 0,
    color: item.color
  })
  .onClick(() => {
    if (this.selectedId === item.id) {
      this.selectedId = -1    // 再次点击取消选中
    } else {
      this.selectedId = item.id  // 选中该分类
    }
  })
}

这个 @Builder 方法封装了单个分类卡片的构建逻辑,接收一个 FirstAidCategory 参数。几个关键设计点:

动态背景色:通过三元表达式实现选中/未选中状态的背景色切换。选中状态使用分类主题色叠加 18(十六进制 24)的透明度(item.color + '18'),形成柔和的高亮效果;未选中时使用浅灰色(#F7F8FA)。

动态边框:选中时显示 2px 宽的主题色边框,未选中时边框宽度为 0,完全隐藏。

点击交互:通过 .onClick() 注册点击事件,实现切换选中/取消选中的逻辑。这是一个典型的 toggle 模式——再次点击已选中的卡片会取消选中。

垂直居中:卡片内容通过 .justifyContent(FlexAlign.Center) 实现垂直居中,.width('100%').height('100%') 确保卡片撑满 GridItem 的全部空间。

六、List 步骤详情实现

6.1 DetailListBuilder 构建器结构

@Builder
DetailListBuilder() {
  List() {
    ForEach(this.categories, (category: FirstAidCategory) => {
      if (this.selectedId === category.id) {
        ListItem() {
          Column() {
            // 1. 分类标题区
            // 2. 步骤列表(嵌套 ForEach)
            // 3. 底部 120 提示
          }
        }
      }
    })
  }
  .width('100%')
  .layoutWeight(1)
  .backgroundColor('#FAFAFA')
  .divider({ strokeWidth: 0 })
}

DetailListBuilder 是页面下半部分的核心构建器。它使用 List 组件包裹步骤内容,通过外层 ForEach 遍历所有分类,再用 if 条件筛选出当前选中的分类进行渲染。

.layoutWeight(1) 使 List 占据 build() 方法中 Column 布局的全部剩余空间。.divider({ strokeWidth: 0 }) 隐藏 List 组件的默认分割线,改为在各步骤之间自定义分割线样式。

6.2 嵌套 ForEach 渲染步骤

ForEach(category.steps, (step: FirstAidStep, index: number) => {
  ListItem() {
    Column() {
      if (index > 0) {
        Divider()
          .color('#E8E8E8')
          .margin({ left: 29, top: 0, bottom: 0 })
      }
      this.StepItemBuilder(step, category.color)
    }
  }
})

这里的嵌套 ForEach 是 ArkTS 中处理层级数据的常见模式。外层遍历分类,内层遍历步骤。每个步骤包裹在 ListItem 中,形成 List 的子项。非首个步骤前方添加一条缩进的分割线(左偏移 29vp,与步骤编号圆圈的宽度对齐),营造步骤之间的视觉连接感。

6.3 StepItemBuilder 步骤项构建器

@Builder
StepItemBuilder(step: FirstAidStep, color: string) {
  Row() {
    // 左侧:步骤编号圆圈
    Column() {
      Text(step.step.toString())
        .fontSize(14)
        .fontWeight(FontWeight.Bold)
        .fontColor('#FFFFFF')
    }
    .width(28)
    .height(28)
    .borderRadius(14)
    .backgroundColor(color)
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)

    // 右侧:步骤内容
    Column() {
      Text(step.title)
        .fontSize(16)
        .fontWeight(FontWeight.Medium)
        .fontColor('#1A1A1A')

      Text(step.description)
        .fontSize(14)
        .fontColor('#666666')
        .margin({ top: 4 })
        .lineHeight(20)

      // 可选的警告提示
      if (step.warning) {
        Row() {
          Text('⚠')
          Text(step.warning!)
            .fontColor('#E63946')
        }
        .backgroundColor('#FFF3F3')
        .borderRadius(6)
      }
    }
    .alignItems(HorizontalAlign.Start)
    .layoutWeight(1)
    .margin({ left: 12 })
  }
  .width('100%')
  .padding({ left: 16, right: 16, top: 12, bottom: 12 })
}

每个步骤项采用 Row 水平布局,左侧为圆形步骤编号,右侧为步骤标题、描述和可选的警告提示。

步骤编号圆圈:宽高 28vp 的正圆,使用分类主题色作为背景,白色粗体数字作为内容。.borderRadius(14)(宽高的一半)确保完美圆形。

警告提示区域:通过 if (step.warning) 条件渲染,仅在步骤存在警告信息时才显示。使用浅红色背景(#FFF3F3)和红色文字(#E63946),搭配警告符号,在视觉上引起用户注意。

布局细节:右侧内容区使用 .alignItems(HorizontalAlign.Start) 左对齐,.layoutWeight(1) 撑满剩余空间,.margin({ left: 12 }) 与编号圆圈保持 12vp 间距。

七、顶部标题栏与空状态设计

7.1 顶部标题栏

Row() {
  Text('🏥')
    .fontSize(24)
  Text('急救指南')
    .fontSize(22)
    .fontWeight(FontWeight.Bold)
    .fontColor('#FFFFFF')
    .margin({ left: 8 })
}
.width('100%')
.height(56)
.padding({ left: 20 })
.alignItems(VerticalAlign.Center)
.backgroundColor('#E63946')

标题栏采用红色背景(#E63946)搭配白色文字,形成强烈的视觉识别性。高度固定为 56vp,这是 Material Design 和 HarmonyOS 中标准的顶部栏高度。左侧内边距 20vp,与 Grid 区域的内边距保持一致,形成对齐的视觉节奏。

7.2 空状态提示

Column() {
  Text('👆')
    .fontSize(48)
    .margin({ bottom: 16 })

  Text('请在上方选择急救场景')
    .fontSize(16)
    .fontColor('#999999')

  Text('查看详细操作步骤')
    .fontSize(14)
    .fontColor('#CCCCCC')
    .margin({ top: 8 })
}
.width('100%')
.layoutWeight(1)
.justifyContent(FlexAlign.Center)

当用户尚未选择任何急救场景时,页面下方显示一个友好的引导提示。居中的手指指向图标配合灰色文字,清晰地传达"请先选择分类"的交互引导。两级文字使用不同灰度(#999999 和 #CCCCCC)区分主副信息层次。

八、ForEach 与 @Builder 的配合模式

8.1 @Builder 装饰器

@Builder 是 ArkUI 中用于定义可复用 UI 片段的装饰器。与 @Component 不同,@Builder 方法不创建独立的组件实例,而是将构建逻辑内联展开到父组件的渲染树中。

在本应用中,定义了三个 @Builder 方法:

构建器名称 职责 参数
GridItemBuilder 构建单个分类卡片 item: FirstAidCategory
StepItemBuilder 构建单个步骤项 step: FirstAidStep, color: string
DetailListBuilder 构建完整的步骤详情列表 无(使用组件状态)

8.2 ForEach 的使用规范

ArkTS 中的 ForEach 方法接收三个参数:

ForEach(
  arr: Array,           // 数据源数组
  (item: T, index: number) => void,  // 项构建函数
  (item: T) => string  // 可选的 key 生成函数
)

在本项目中,外层 ForEach 使用 categories 数组,内层 ForEach 使用 category.steps 数组。每层 ForEach 的 item 构建函数中都通过 this 引用组件的 @Builder 方法来构建具体 UI。

8.3 开发中遇到的关键问题

在实际开发过程中,遇到一个典型的编译错误:

ERROR: Property 'width' does not exist on type 'void'

这个问题出现在尝试对 @Builder 方法的调用结果进行链式属性调用时:

// 错误写法
this.DetailListBuilder()
  .width('100%')
  .layoutWeight(1)
  .backgroundColor('#FAFAFA')

原因分析:在 ArkTS 中,@Builder 方法的返回类型是 void,它不会返回可操作的组件对象。因此,不能在调用 @Builder 方法后继续链式调用 .width() 等组件属性方法。

解决方案:将需要的属性设置移入 @Builder 方法内部的顶层组件上:

// 正确写法
@Builder
DetailListBuilder() {
  List() {
    // ... 内容
  }
  .width('100%')        // 属性写在 Builder 内部
  .layoutWeight(1)
  .backgroundColor('#FAFAFA')
}

// 调用处不再链式调用
this.DetailListBuilder()

这是 ArkTS 开发中一个常见且容易踩坑的细节,对于熟悉 React 或 Vue 等前端框架的开发者尤其需要注意——@Builder 不是返回 JSX 元素的函数,而是直接操作渲染树的构建器。

九、颜色系统与视觉设计

9.1 配色方案

应用整体采用红色系为主色调,契合"急救"主题:

用途 色值 说明
标题栏背景 #E63946 标准急救红
烫伤主题色 #FF6B35 橙色,传递热源感知
心肺复苏主题色 #E63946 红色,对应心脏主题
止血主题色 #A4133C 深红色,对应血液
步骤背景 #FAFAFA 极浅灰,区分信息层级
未选中卡片背景 #F7F8FA 冷灰色
选中卡片背景 {color}18 主题色 10% 透明度叠加
警告背景 #FFF3F3 浅红底色
警告文字 #E63946 标准警告红
主标题文字 #1A1A1A 近黑色
副标题文字 #333333 深灰
说明文字 #666666 中灰
引导文字 #999999 浅灰
辅助文字 #CCCCCC 极浅灰

9.2 间距系统

应用采用一致的间距规范:

  • 页面级外边距:16vp(Grid 区域和步骤内容区)
  • 卡片内边距:居中对齐,通过 Flex 布局自动分配
  • 标题栏内边距:左 20vp,与 Grid 区域形成视觉对齐
  • 步骤项内边距:左右 16vp,上下 12vp
  • 元素间距:8vp(小间距)、12vp(中间距)、16vp(大间距)

十、底部 120 提示与安全保障

Row() {
  Text('如遇紧急情况请立即拨打 ')
    .fontSize(13)
    .fontColor('#999999')
  Text('120')
    .fontSize(16)
    .fontWeight(FontWeight.Bold)
    .fontColor('#E63946')
}
.width('100%')
.justifyContent(FlexAlign.Center)
.padding(16)

在每个急救场景的步骤列表底部,都固定显示"如遇紧急情况请立即拨打 120"的提示。数字"120"使用加粗红色字体突出显示,确保用户在任何情况下都能快速找到急救电话信息。这个设计体现了急救应用的核心原则——生命安全永远是第一位的,应用中的知识仅供参考,不能替代专业医疗救助。

十一、开发环境与编译运行

11.1 环境要求

开发本应用需要以下环境配置:

  • IDE:DevEco Studio 5.0+(HarmonyOS NEXT 专用 IDE)
  • SDK:HarmonyOS NEXT SDK
  • 语言:ArkTS(基于 TypeScript 扩展)
  • Node.js:16+ (用于 hvigor 构建工具链)

11.2 编译与运行

  1. 在 DevEco Studio 中打开项目
  2. 等待 hvigor 自动同步依赖
  3. 连接 HarmonyOS 模拟器或真机设备
  4. 点击 Run 按钮或执行 hvigorw assembleHap 命令
  5. 编译成功后自动安装并启动应用

11.3 常见编译错误处理

在开发过程中,以下是需要特别注意的 ArkTS 编译规范:

@Builder 返回值问题:如前文所述,@Builder 方法返回 void,不可链式调用组件属性。

类型安全要求:ArkTS 是 TypeScript 的严格超集,所有变量必须有明确类型声明。例如 @State selectedId: number = -1 必须显式标注 number 类型。

空值处理:可选属性访问需要使用 ! 非空断言操作符(如 step.warning!),或使用 if 条件判断后访问。

十二、功能扩展与优化方向

当前应用作为急救指南的基础版本已经具备核心功能,以下是一些可以进一步探索的优化方向:

12.1 数据持久化

将急救知识数据从内联常量迁移至本地 JSON 文件或轻量级数据库(如 relationalStore),支持后续运营更新内容而无需重新编译发版。

12.2 多媒体辅助

为每个急救步骤添加示意图或短视频指引,利用 Image 和 Video 组件实现更直观的操作演示。可以将图片资源放在 resources/base/media/ 目录中,通过 $r('app.media.xxx') 引用。

12.3 搜索功能

在顶部添加搜索栏,支持用户通过关键词快速定位到对应的急救步骤,提升紧急情况下的检索效率。

12.4 收藏与历史记录

添加"收藏"功能,允许用户将常用的急救场景加入收藏夹;添加"最近查看"历史记录,方便快速回访。

12.5 无障碍适配

添加 accessibilityText 属性和焦点管理,支持屏幕阅读器(VoiceOver/TalkBack)朗读,确保视障用户也能获取急救信息。

12.6 深色模式适配

当前应用仅定义了浅色主题,可以通过定义 dark 模式的颜色变量,结合 @StorageProp 或 media query 实现系统级深色模式的自动切换。

十三、ArkTS 声明式 UI 开发心得

通过本项目的实践,总结几点 ArkTS 声明式 UI 开发的核心要点:

声明式思维:ArkTS 采用类似 SwiftUI 和 Jetpack Compose 的声明式 UI 范式。开发者只需要描述"UI 应该是什么样子",而不需要手动操作 DOM 或 View 树。框架会自动计算差异并更新界面。

Builder 模式@Builder 是 ArkTS 中实现 UI 代码复用的主要手段。将可复用的 UI 片段提取为 @Builder 方法,既保持了代码的可读性,又避免了组件创建的开销。

状态驱动 UI@State 状态变量是 UI 更新的唯一触发源。所有 UI 变化都应该通过修改状态变量来驱动,而非手动调用刷新方法。

组合优于继承:ArkTS 鼓励通过组合 @Builder 方法来构建复杂界面,而非通过类继承来扩展组件能力。这种模式更灵活、更易于维护。

类型安全:作为 TypeScript 的严格超集,ArkTS 强制类型检查。虽然增加了编码时的类型声明工作量,但有效减少了运行时错误,提升了代码质量。

十四、总结

本文从零开始,详细介绍了使用 ArkTS 开发鸿蒙原生急救指南应用的完整过程。从项目结构设计、数据模型定义,到 Grid 网格分类展示、List 步骤详情列表的实现,再到状态管理、视觉设计和编译调试中的问题解决,涵盖了 HarmonyOS 应用开发的方方面面。

该急救指南应用虽然代码量不大(约 290 行),但完整展示了 ArkTS 声明式 UI 开发的核心模式:@State 驱动响应式更新、@Builder 实现组件复用、ForEach 处理列表渲染、条件渲染实现视图切换。这些都是 HarmonyOS 应用开发的基础能力。

掌握这些基础知识后,开发者可以进一步探索更多高级特性,如 Navigation 路由跳转、网络请求、本地数据持久化、分布式能力等,构建更加丰富的鸿蒙原生应用。急救知识的传播本身就是一个有意义的事业,希望本文的分享能够帮助更多开发者投入到 HarmonyOS 生态的建设中来。

声明:本文中的急救操作步骤仅供参考学习,在实际紧急情况下请务必第一时间拨打 120 急救电话,听从专业医护人员的指导。


项目信息

  • 开发语言:ArkTS
  • 开发框架:ArkUI 声明式 UI
  • 目标平台:HarmonyOS NEXT
  • 核心组件:Grid、List、ForEach、@Builder、@State
  • 源代码文件:entry/src/main/ets/pages/Index.ets
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐