很多 HarmonyOS 教程存在一个问题:
示例都很"碎",写完也不知道怎么组合成一个真正的应用。
这篇文章我们反过来做一件事:
👉 从 0 开始,完整地写一个 HarmonyOS 应用
👉 包含页面、状态、组件拆分、数据流、业务逻辑
👉 写完后你能清楚回答:
"如果让我再加一个功能,我该改哪里?"
一、我们要做一个什么应用?
先定目标,避免迷路。
🎯 应用目标:一个「任务清单 App」
功能很简单,但足够完整:
-
添加任务
-
删除任务
-
显示任务列表
-
统计任务数量
-
组件拆分清晰
-
使用 HarmonyOS 推荐写法
这是很多真实 App 的"雏形"。
二、项目结构设计(非常重要)
不要一上来就写代码,先想结构。
推荐结构(教学友好)
entry/
├─ pages/
│ └─ Index.ets // 页面入口
├─ components/
│ ├─ TaskInput.ets // 输入组件
│ ├─ TaskItem.ets // 单条任务
│ └─ TaskList.ets // 列表组件
└─ model/
└─ TaskModel.ets // 数据模型
📌 页面 ≠ 组件 ≠ 数据模型
📌 这是 HarmonyOS 开发中非常重要的分层思想
三、第一步:定义数据模型(状态源头)
我们先从"数据"开始。
model/TaskModel.ets
@ObservedV2
export class Task {
id: number
title: string
constructor(id: number, title: string) {
this.id = id
this.title = title
}
}
@ObservedV2
export class TaskStore {
tasks: Task[] = []
addTask(title: string) {
this.tasks.push(new Task(Date.now(), title))
}
removeTask(id: number) {
this.tasks = this.tasks.filter(item => item.id !== id)
}
get count(): number {
return this.tasks.length
}
}
教学重点解释
-
@ObservedV2👉 告诉系统:这是可观察的数据源
-
TaskStore👉 类似 Vuex / Redux 的 store
-
数据逻辑集中管理
👉 UI 不直接操作数组
四、第二步:页面入口(应用总控)
pages/Index.ets
import { TaskStore } from '../model/TaskModel'
import { TaskInput } from '../components/TaskInput'
import { TaskList } from '../components/TaskList'
@ComponentV2
struct Index {
@Local store = new TaskStore()
build() {
Column({ space: 12 }) {
Text("📋 我的任务清单")
.fontSize(22)
.fontWeight(FontWeight.Bold)
Text(`当前任务数:${this.store.count}`)
TaskInput({ onAdd: (title) => this.store.addTask(title) })
TaskList({
tasks: this.store.tasks,
onDelete: (id) => this.store.removeTask(id)
})
}
.padding(16)
}
}
教学重点
-
@Local store👉 页面私有状态
-
页面只做三件事:
-
组合组件
-
管理数据
-
传递事件
-
📌 页面 = 组装者,不写具体 UI 细节
五、第三步:输入组件(事件驱动)
components/TaskInput.ets
@ComponentV2
export struct TaskInput {
@Local text: string = ''
@Event onAdd: (title: string) => void
build() {
Row({ space: 8 }) {
TextInput({ placeholder: '输入任务内容' })
.onChange(value => this.text = value)
.layoutWeight(1)
Button("添加")
.onClick(() => {
if (this.text.trim().length > 0) {
this.onAdd(this.text)
this.text = ''
}
})
}
}
}
教学重点
-
@Event👉 子组件向父组件"汇报事件"
-
子组件:
-
不关心数据存哪里
-
只负责触发行为
-
📌 这是非常标准、推荐的组件通信方式
六、第四步:列表组件(参数 + 事件)
components/TaskList.ets
import { Task } from '../model/TaskModel'
import { TaskItem } from './TaskItem'
@ComponentV2
export struct TaskList {
@Param tasks: Task[]
@Event onDelete: (id: number) => void
build() {
Column({ space: 8 }) {
ForEach(this.tasks, (item: Task) => {
TaskItem({
task: item,
onDelete: this.onDelete
})
}, item => item.id.toString())
}
}
}
教学重点
-
@Param👉 父组件传入的数据
-
ForEach👉 列表渲染的标准方式
-
key 很重要
👉
item.id保证渲染稳定
七、第五步:单条任务组件(最小职责)
components/TaskItem.ets
import { Task } from '../model/TaskModel'
@ComponentV2
export struct TaskItem {
@Param task: Task
@Event onDelete: (id: number) => void
build() {
Row({ space: 12 }) {
Text(this.task.title)
.layoutWeight(1)
Button("删除")
.onClick(() => this.onDelete(this.task.id))
}
.padding(8)
.backgroundColor('#f5f5f5')
.borderRadius(8)
}
}
📌 一个组件只做一件事
📌 不操作全局数据
📌 不关心存储逻辑
八、到这里,我们已经完成了什么?
你已经完成了一个:
✔ 可运行
✔ 有完整业务逻辑
✔ 有数据模型
✔ 有组件拆分
✔ 有父子通信
✔ 使用 V2 状态管理
✔ 符合 HarmonyOS 设计思想
的完整应用。
九、如果我要扩展功能,该怎么做?
示例 1:加"完成状态"
-
给
Task增加done: boolean -
在
TaskItem增加勾选按钮 -
TaskStore增加toggleDone()
UI 不用大改。
示例 2:数据持久化
-
在
TaskStore中:-
使用 Preferences 存储
-
启动时加载
-
-
页面完全不用动
📌 好架构的标志:改动点集中
十、这篇文章你真正应该学到的不是代码
而是这 5 个核心思想:
-
状态集中管理
-
组件职责单一
-
数据向下流,事件向上传
-
UI 不直接操作业务
-
V2 状态管理更适合真实项目
结语
写 HarmonyOS 应用,真正的难点不是 API,而是"如何组织代码"。
如果你能按照这篇文章的方式写完一遍,
你已经超过了大多数只会抄 Demo 的开发者。