很多 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 的开发者。