HarmonyOS7 综合实战:从 0 搭一个待办 App
·
文章目录
前言
本篇我们主要做的是从零做一个能跑的"待办事项 App"——增、删、改、持久化、动画、主题全用上。

做完这个,你对 HarmonyOS 开发会有"整体感"。代码我分模块给你,跟着敲就能跑。
先想清楚要什么
一个待办 App 的最小功能:
- 列表展示待办项(标题、是否完成)
- 新增待办
- 勾选完成(带过渡动画)
- 删除待办
- 数据持久化(关掉再开还在)

- 深色模式切换(顺手加)
数据模型 & 存储
用 Preferences 存简单列表(前面讲过的)。先定义模型:
代码实现
interface Todo {
id: number
title: string
done: boolean
}
// 存储封装
import { preferences } from '@kit.ArkData'
let prefs: preferences.Preferences
async function initStore() {
prefs = await preferences.getPreferences(getContext(), 'todo')
}
async function save(list: Todo[]) {
await prefs.put('list', JSON.stringify(list))
await prefs.flush()
}
async function load(): Promise<Todo[]> {
const s = await prefs.get('list', '[]') as string
return JSON.parse(s) as Todo[]
}
- 用 JSON 把数组序列化存进 Preferences,简单够用。
save写完必须flush,否则重启丢失(老坑了)。
主页面:列表 + 状态
@Entry
@ComponentV2
struct TodoApp {
@Local todos: Todo[] = []
@Local input: string = ''
@Local dark: boolean = false
aboutToAppear() {
initStore().then(() => load()).then(list => this.todos = list)
}
build() {
Column() {
// 顶部:标题 + 主题切换
Row() {
Text('我的待办').fontSize(22).fontWeight(FontWeight.Bold)
Blank()
Toggle({ type: ToggleType.Switch, isOn: this.dark })
.onChange(v => this.dark = v)
}.padding(12)
// 输入区
Row() {
TextInput({ placeholder: '写点什么...', text: this.input })
.onChange(v => this.input = v).layoutWeight(1)
Button('添加').onClick(() => this.add())
}.padding({ left: 12, right: 12, bottom: 8 })
// 列表
List() {
ForEach(this.todos, (t: Todo) => {
ListItem() {
this.TodoRow(t)
}
}, (t: Todo) => t.id.toString())
}
.layoutWeight(1)
}
.backgroundColor(this.dark ? '#1A1A1A' : '#F5F5F5')
.width('100%').height('100%')
}
}

讲解:
aboutToAppear里初始化存储并加载已有数据。ForEach渲染列表,用id当唯一键(重要,前面踩坑篇讲过)。- 主题切换直接改
dark状态,根背景随之变化。
列表项:勾选 + 删除 + 动画
@Builder
TodoRow(t: Todo) {
Row() {
Checkbox({ name: t.id.toString(), group: 'todo' })
.select(t.done)
.onChange(v => this.toggle(t.id, v))
Text(t.title)
.fontSize(16)
.decoration({ type: t.done ? TextDecorationType.LineThrough : TextDecorationType.None })
.fontColor(t.done ? '#999999' : (this.dark ? '#EEEEEE' : '#333333'))
.layoutWeight(1)
Button('删').onClick(() => this.remove(t.id))
}
.padding(12)
.backgroundColor(this.dark ? '#2A2A2A' : '#FFFFFF')
.borderRadius(8)
.margin({ left: 12, right: 12, bottom: 8 })
}
toggle(id: number, done: boolean) {
animateTo({ duration: 250, curve: Curve.EaseOut }, () => {
this.todos = this.todos.map(t => t.id === id ? { ...t, done } : t)
})
this.persist()
}
Checkbox勾选触发toggle,用animateTo让"划线 + 变灰"平滑过渡。decoration给完成的项加删除线,视觉反馈清晰。- 改完立刻
persist()存盘。
增与删
add() {
if (!this.input.trim()) return
const item: Todo = { id: Date.now(), title: this.input.trim(), done: false }
this.todos = [item, ...this.todos] // 新项置顶
this.input = ''
this.persist()
}
remove(id: number) {
animateTo({ duration: 200 }, () => {
this.todos = this.todos.filter(t => t.id !== id)
})
this.persist()
}
persist() {
save(this.todos) // 防抖可后续优化
}
- 新增用
Date.now()当唯一 id(够用,且天然唯一)。 - 删除用
filter,配合animateTo有消失动画。 - 每次变更都
persist()落盘,保证持久化。
这个 App 用到了哪些知识
| 能力 | 来自哪篇 |
|---|---|
| Column/Row 布局 | 布局篇 |
| @Local 状态驱动 | 状态原理篇 |
| ForEach 唯一键 | 列表踩坑篇 |
| Checkbox/TextInput/Toggle | 表单组件 |
| animateTo 动画 | 属性动画篇 |
| Preferences 存储 | 轻量存储篇 |
| aboutToAppear 初始化 | 生命周期篇 |
| 主题切换 | 深色模式篇 |
你看,一个看似完整的小 app,就是把前面零散的知识点"拼"起来。这就是实战的意义:知识不再是孤岛。
常见误区(小白必踩)
| 误区 | 说明 |
|---|---|
| 唯一键用下标 | ForEach 用下标当键,删除会错乱,用 id(如 Date.now())当唯一键。 |
改完不 flush |
Preferences 存待办忘了 flush,重启数据全丢。 |
勾选用 animateTo 套错对象 |
动画要包在状态变更上,包错地方就没过渡效果。 |
| 主题不持久化 | 深色模式切换后没存 Preferences,下次打开又回浅色。 |
下面这段代码可以直接复制到 DevEco Studio 里运行。建议你边读边敲,改一改文末「动手改一改」里的参数,亲眼看看效果。
完整可运行示例:待办 App 的持久化
把前面综合实战里的待办数据落盘,关掉 App 再开数据还在。
核心代码
// 用 Preferences 持久化待办列表
import { preferences } from '@kit.ArkData'
async function saveTodos(list: string[]) {
const pref = await preferences.getPreferences(getContext(), 'todo')
await pref.put('list', JSON.stringify(list)) // 数组序列化后存
await pref.flush()
}
async function loadTodos(): Promise<string[]> {
const pref = await preferences.getPreferences(getContext(), 'todo')
const s = pref.get('list', '[]') as string
return JSON.parse(s) as string[]
}
你会看到什么:在综合实战的待办 App 里接上这两个函数——新增待办后调用 saveTodos,aboutToAppear 时调用 loadTodos 恢复。这样即使杀掉进程,下次打开待办仍在。
动手改一改:
- 把
Preferences换成relationalStore,支持「按完成状态筛选」。 - 给每条待办加
id与done字段,做「已完成划线」。 - 用分布式 KV 把待办同步到平板,体验多端一致。
写在最后
这个待办 App 虽小,却是 HarmonyOS 开发的"微缩全景"——布局、状态、列表、动画、存储、主题全齐了。
建议你别只是看,把代码敲进 DevEco 真跑一遍,再自己加个功能(比如"编辑待办"“按完成筛选”)。当你能把零散知识拼成完整产品,才算真正入门 HarmonyOS 开发。
更多推荐



所有评论(0)