备忘录实战开发 - 文本输入处理与记事效率工具-鸿蒙ArkTS源码完成

一、概述
备忘录应用是一款基于HarmonyOS ArkTS框架开发的待办事项管理工具,提供了完整的待办事项管理功能,包括添加、标记完成、删除、筛选等核心操作。该应用展示了HarmonyOS声明式UI开发的核心模式,是学习ArkTS开发的经典案例。
1.1 应用功能清单
| 功能模块 | 描述 |
|---|---|
| 添加待办 | 通过输入框添加新的待办事项 |
| 完成标记 | 通过复选框切换待办事项的完成状态 |
| 删除待办 | 单条删除指定的待办事项 |
| 筛选查看 | 支持全部/待完成/已完成三种筛选模式 |
| 批量清理 | 一键清除所有已完成的待办事项 |
| 数据统计 | 显示总数、待完成数、已完成数 |
| 数据持久化 | 自动保存到本地存储,重启后数据不丢失 |
1.2 技术栈概览
本应用的技术架构体现了HarmonyOS应用开发的核心特性:
- UI框架:ArkUI声明式开发范式
- 状态管理:@State装饰器实现响应式数据绑定
- 列表渲染:ForEach循环渲染动态列表
- 数据持久化:AppStorage + dataPreferences实现本地存储
- 组件复用:CommonTitleBar通用标题栏组件
- 路由管理:AppRouter页面导航管理
二、架构分析
2.1 整体架构
备忘录应用采用标准的ArkUI单页面架构,所有业务逻辑和UI构建都在一个@Component struct中完成。应用结构清晰,分为以下几个层次:
┌─────────────────────────────────────┐
│ Memo页面 │
│ ┌─────────────────────────────┐ │
│ │ CommonTitleBar │ │
│ │ (标题栏) │ │
│ └─────────────────────────────┘ │
│ ┌─────────────────────────────┐ │
│ │ 输入区域 │ │
│ │ TextField + Button │ │
│ └─────────────────────────────┘ │
│ ┌─────────────────────────────┐ │
│ │ 筛选按钮组 │ │
│ │ 全部 | 待完成 | 已完成 │ │
│ └─────────────────────────────┘ │
│ ┌─────────────────────────────┐ │
│ │ 待办列表(Scroll) │ │
│ │ ForEach渲染待办项 │ │
│ └─────────────────────────────┘ │
│ ┌─────────────────────────────┐ │
│ │ 统计与操作栏 │ │
│ │ 统计数据 + 清除已完成按钮 │ │
│ └─────────────────────────────┘ │
└─────────────────────────────────────┘
2.2 数据流分析
应用采用单向数据流模式,数据变化驱动UI自动更新:
- 初始化阶段:aboutToAppear回调触发app_loadMemos,从AppStorage读取已保存的待办数据
- 用户交互阶段:用户操作触发状态变更(@State变量修改)
- 数据持久化阶段:每次状态变更后自动调用app_saveMemos保存到本地
- UI更新阶段:ArkUI框架自动检测@State变量变化,触发相关UI组件重新渲染
用户操作 → @State变更 → 自动保存 → UI自动更新
↑ │
└────────── AppStorage ────────────────┘
2.3 模块依赖关系
pages/life/Memo.ets
├── components/CommonTitleBar.ets
│ └── utils/router.ets
└── utils/storage.ets
└── @ohos.data.preferences
三、核心代码详解
3.1 数据结构定义
备忘录应用使用TypeScript的interface来定义待办事项的数据结构,这种方式在ArkTS中是标准的对象类型定义方式。
interface App_MemoItem {
app_id: string;
app_content: string;
app_completed: boolean;
app_createdAt: string;
}
字段说明:
| 字段名 | 类型 | 描述 |
|---|---|---|
| app_id | string | 待办事项的唯一标识符,使用时间戳生成 |
| app_content | string | 待办事项的文本内容 |
| app_completed | boolean | 完成状态,true表示已完成 |
| app_createdAt | string | 创建时间,格式为本地化日期时间字符串 |
代码解读:
app_id字段使用Date.now().toString()生成,确保每个待办事项都有全局唯一的标识app_completed是布尔类型,用于标记完成状态,这在待办类应用中是最核心的状态字段app_createdAt记录创建时间,方便用户了解待办的添加时间
// 创建新待办时的数据结构
const app_newItem: App_MemoItem = {
app_id: Date.now().toString(),
app_content: this.app_newMemo.trim(),
app_completed: false,
app_createdAt: new Date().toLocaleString('zh-CN')
};
命名规范说明:
应用所有变量和函数都以app_前缀开头,这是该项目的命名约定,用于:
- 明确标识这是应用层代码
- 避免与系统API命名冲突
- 提高代码可读性和可维护性
3.2 状态管理
备忘录应用的状态管理采用ArkTS提供的@State装饰器,这是声明式UI框架中最基本的状态管理机制。
@State app_memos: App_MemoItem[] = [];
@State app_newMemo: string = '';
@State app_filter: 'all' | 'active' | 'completed' = 'all';
三个核心状态变量:
| 状态变量 | 类型 | 默认值 | 用途 |
|---|---|---|---|
| app_memos | App_MemoItem[] | [] | 存储所有待办事项的数组 |
| app_newMemo | string | ‘’ | 输入框的实时绑定值 |
| app_filter | ‘all’ | ‘active’ | ‘completed’ | ‘all’ | 当前筛选模式 |
@State装饰器的作用机制:
@State是ArkTS中的响应式状态管理装饰器,它的核心机制如下:
- 私有性:@State修饰的变量是组件私有的,只能在当前组件内访问和修改
- 响应式:当@State变量值发生变化时,ArkUI框架会自动触发UI重新渲染
- 追踪性:框架会追踪@State变量的所有引用,在变量变化时精准更新相关UI组件
// 状态变化的典型场景:添加新待办
app_addMemo(): void {
if (this.app_newMemo.trim() === '') {
return;
}
const app_newItem: App_MemoItem = {
app_id: Date.now().toString(),
app_content: this.app_newMemo.trim(),
app_completed: false,
app_createdAt: new Date().toLocaleString('zh-CN')
};
this.app_memos.unshift(app_newItem); // 修改app_memos数组
this.app_newMemo = ''; // 清空输入框
this.app_saveMemos(); // 持久化保存
}
当app_memos数组发生变化时:
- ForEach会自动检测到数组变化
- 列表会重新渲染,显示新增的待办项
- 统计栏的数字也会自动更新
筛选状态的应用:
// 筛选状态影响按钮样式
Button('全部')
.backgroundColor(this.app_filter === 'all' ? $r('app.color.app_color_primary') : $r('app.color.app_color_white'))
.fontColor(this.app_filter === 'all' ? $r('app.color.app_color_white') : $r('app.color.app_color_text_primary'))
.onClick(() => this.app_filter = 'all')
Button('待完成')
.backgroundColor(this.app_filter === 'active' ? $r('app.color.app_color_primary') : $r('app.color.app_color_white'))
.onClick(() => this.app_filter = 'active')
Button('已完成')
.backgroundColor(this.app_filter === 'completed' ? $r('app.color.app_color_primary') : $r('app.color.app_color_white'))
.onClick(() => this.app_filter = 'completed')
筛选按钮通过条件表达式动态改变背景色和字体颜色,当前选中的筛选模式会显示为主色调(蓝色),未选中的显示为白色。
3.3 数据持久化
数据持久化是备忘录应用的核心功能之一,确保用户数据在应用关闭后不会丢失。应用使用AppStorage工具类配合HarmonyOS的dataPreferences API实现本地存储。
AppStorage工具类实现:
import dataPreferences from '@ohos.data.preferences';
import type common from '@ohos.app.ability.common';
let app_pref_instance: dataPreferences.Preferences | null = null;
export class AppStorage {
static async app_init(app_context: common.UIAbilityContext): Promise<void> {
try {
app_pref_instance = await dataPreferences.getPreferences(app_context, 'app_storage');
} catch (error) {
console.error(`存储初始化失败: ${error}`);
}
}
static async app_setString(app_key: string, app_value: string): Promise<void> {
if (app_pref_instance !== null) {
try {
await app_pref_instance.putSync(app_key, app_value);
await app_pref_instance.flushSync();
} catch (error) {
console.error(`存储设置失败: ${error}`);
}
}
}
static app_getString(app_key: string, app_defaultValue: string): string {
if (app_pref_instance !== null) {
try {
return app_pref_instance.getSync(app_key, app_defaultValue) as string;
} catch (error) {
console.error(`存储获取失败: ${error}`);
return app_defaultValue;
}
}
return app_defaultValue;
}
// ... 其他方法类似
}
AppStorage核心方法说明:
| 方法名 | 参数 | 返回值 | 功能 |
|---|---|---|---|
| app_init | UIAbilityContext | Promise | 初始化Preferences实例 |
| app_setString | key, value | Promise | 异步存储字符串 |
| app_getString | key, defaultValue | string | 同步读取字符串 |
| app_setNumber | key, value | Promise | 异步存储数字 |
| app_getNumber | key, defaultValue | number | 同步读取数字 |
| app_setBoolean | key, value | Promise | 异步存储布尔值 |
| app_getBoolean | key, defaultValue | boolean | 同步读取布尔值 |
| app_delete | key | Promise | 删除指定key |
| app_clear | - | Promise | 清空所有数据 |
Memo页面中的存储调用:
app_loadMemos(): void {
const app_stored: string = app_getString('memo_items', '[]');
try {
this.app_memos = JSON.parse(app_stored);
} catch (error) {
this.app_memos = [];
}
}
app_saveMemos(): void {
app_setString('memo_items', JSON.stringify(this.app_memos));
}
存储原理剖析:
- 数据序列化:待办数组通过
JSON.stringify转换为JSON字符串 - 键值对存储:使用’memo_items’作为存储键名
- 数据读取:启动时通过
JSON.parse将JSON字符串还原为数组对象 - 容错处理:读取失败时使用空数组作为默认值,确保应用不会崩溃
// 存储的数据格式示例
'memo_items' -> '[{"app_id":"1718600000000","app_content":"买牛奶","app_completed":false,"app_createdAt":"2024/6/17 10:00:00"},...]'
同步与异步的合理使用:
app_getString使用同步读取,因为启动时需要立即获取数据进行渲染app_setString使用异步存储,配合flushSync确保数据写入磁盘- 这种同步读取、异步写入的模式是移动应用开发的常见优化策略
3.4 列表渲染
列表渲染是备忘录应用的核心UI功能,使用ForEach循环实现动态列表的渲染。
ForEach语法结构:
ForEach(this.app_getFilteredMemos(), (app_item: App_MemoItem) => {
// 列表项内容
})
ForEach接收两个参数:
- arr: 要遍历的数组,这里调用
app_getFilteredMemos()获取筛选后的数据 - itemGenerator: 遍历处理函数,接收当前项作为参数
列表项结构:
Row({ space: 12 }) {
Checkbox()
.select(app_item.app_completed)
.selectedColor($r('app.color.app_color_success'))
.onChange(() => this.app_toggleMemo(app_item.app_id))
Text(app_item.app_content)
.width('flexGrow')
.fontSize(16)
.fontColor(app_item.app_completed ? $r('app.color.app_color_text_tertiary') : $r('app.color.app_color_text_primary'))
.decoration({ type: app_item.app_completed ? TextDecorationType.LineThrough : TextDecorationType.None })
Text(app_item.app_createdAt)
.fontSize(12)
.fontColor($r('app.color.app_color_text_tertiary'))
Button() {
Text('删除')
.fontSize(12)
}
.width(50)
.height(32)
.backgroundColor($r('app.color.app_color_danger'))
.fontColor($r('app.color.app_color_white'))
.borderRadius(6)
.onClick(() => this.app_deleteMemo(app_item.app_id))
}
.width('100%')
.height(56)
.backgroundColor($r('app.color.app_color_white'))
.borderRadius(8)
.padding({ left: 16, right: 16 })
.alignItems(VerticalAlign.Center)
列表项组件说明:
| 组件 | 作用 | 关键属性 |
|---|---|---|
| Checkbox | 完成状态切换 | select绑定完成状态,onChange触发切换 |
| Text(内容) | 显示待办文字 | flexGrow占满剩余空间,已完成时显示删除线 |
| Text(时间) | 显示创建时间 | 字体较小,颜色为灰色 |
| Button | 删除操作 | 红色背景,调用app_deleteMemo |
已完成状态的视觉表现:
.fontColor(app_item.app_completed ? $r('app.color.app_color_text_tertiary') : $r('app.color.app_color_text_primary'))
.decoration({ type: app_item.app_completed ? TextDecorationType.LineThrough : TextDecorationType.None })
当app_completed为true时:
- 文字颜色变为灰色(app_color_text_tertiary)
- 文字添加删除线装饰(LineThrough)
- 视觉上明确区分已完成和未完成的待办
空状态处理:
if (this.app_getFilteredMemos().length === 0) {
Column({ space: 8 }) {
Text('暂无待办事项')
.fontSize(16)
.fontColor($r('app.color.app_color_text_tertiary'))
Text('点击上方添加新的待办')
.fontSize(14)
.fontColor($r('app.color.app_color_text_secondary'))
}
.width('100%')
.padding({ top: 60, bottom: 60 })
.alignItems(HorizontalAlign.Center)
}
空状态提示使用条件渲染(if指令),当筛选后的列表为空时显示友好的提示文案,引导用户添加新的待办事项。
3.5 筛选功能实现
筛选功能是备忘录应用的重要交互特性,支持全部、待完成、已完成三种筛选模式。
筛选状态的类型定义:
@State app_filter: 'all' | 'active' | 'completed' = 'all';
使用联合类型定义筛选模式,三种模式含义如下:
| 模式 | 值 | 含义 |
|---|---|---|
| 全部 | ‘all’ | 显示所有待办事项 |
| 待完成 | ‘active’ | 仅显示未完成的待办事项 |
| 已完成 | ‘completed’ | 仅显示已完成的待办事项 |
筛选逻辑实现:
app_getFilteredMemos(): App_MemoItem[] {
switch (this.app_filter) {
case 'active':
return this.app_memos.filter((app_item: App_MemoItem) => !app_item.app_completed);
case 'completed':
return this.app_memos.filter((app_item: App_MemoItem) => app_item.app_completed);
default:
return this.app_memos;
}
}
筛选函数使用switch语句匹配当前筛选模式:
'active':返回app_completed为false的项'completed':返回app_completed为true的项'all':直接返回完整数组
筛选按钮组实现:
Row({ space: 8 }) {
Button('全部')
.width('33%')
.height(40)
.fontSize(14)
.fontWeight(FontWeight.Medium)
.backgroundColor(this.app_filter === 'all' ? $r('app.color.app_color_primary') : $r('app.color.app_color_white'))
.fontColor(this.app_filter === 'all' ? $r('app.color.app_color_white') : $r('app.color.app_color_text_primary'))
.borderRadius(8)
.onClick(() => this.app_filter = 'all')
Button('待完成')
.width('33%')
.height(40)
.fontSize(14)
.fontWeight(FontWeight.Medium)
.backgroundColor(this.app_filter === 'active' ? $r('app.color.app_color_primary') : $r('app.color.app_color_white'))
.fontColor(this.app_filter === 'active' ? $r('app.color.app_color_white') : $r('app.color.app_color_text_primary'))
.borderRadius(8)
.onClick(() => this.app_filter = 'active')
Button('已完成')
.width('33%')
.height(40)
.fontSize(14)
.fontWeight(FontWeight.Medium)
.backgroundColor(this.app_filter === 'completed' ? $r('app.color.app_color_primary') : $r('app.color.app_color_white'))
.fontColor(this.app_filter === 'completed' ? $r('app.color.app_color_white') : $r('app.color.app_color_text_primary'))
.borderRadius(8)
.onClick(() => this.app_filter = 'completed')
}
.width('100%')
.padding({ left: 16, right: 16 })
三个按钮采用均分宽度布局(各占33%),按钮之间间距为8。选中状态通过动态绑定背景色和字体颜色来实现,提供了直观的视觉反馈。
3.6 待办操作方法
备忘录应用提供了完整的待办操作方法,包括添加、完成切换、删除和批量清除。
添加待办:
app_addMemo(): void {
if (this.app_newMemo.trim() === '') {
return;
}
const app_newItem: App_MemoItem = {
app_id: Date.now().toString(),
app_content: this.app_newMemo.trim(),
app_completed: false,
app_createdAt: new Date().toLocaleString('zh-CN')
};
this.app_memos.unshift(app_newItem);
this.app_newMemo = '';
this.app_saveMemos();
}
添加逻辑说明:
- 首先校验输入内容,空白内容直接返回不处理
- 使用
trim()去除首尾空格,避免无效空白待办 - 使用
unshift()将新待办添加到数组头部,新待办显示在列表最上方 - 生成唯一ID使用时间戳
Date.now().toString() - 创建完成后清空输入框
- 自动触发保存持久化
完成状态切换:
app_toggleMemo(app_id: string): void {
const app_index: number = this.app_memos.findIndex((app_item: App_MemoItem) => app_item.app_id === app_id);
if (app_index !== -1) {
this.app_memos[app_index].app_completed = !this.app_memos[app_index].app_completed;
this.app_saveMemos();
}
}
切换逻辑说明:
- 根据ID查找待办在数组中的索引位置
- 使用
findIndex遍历数组匹配app_id - 找到后取反
app_completed布尔值 - 触发保存操作
删除待办:
app_deleteMemo(app_id: string): void {
this.app_memos = this.app_memos.filter((app_item: App_MemoItem) => app_item.app_id !== app_id);
this.app_saveMemos();
}
删除逻辑说明:
- 使用
filter方法创建新数组,排除要删除的项 - 通过ID匹配确定要排除的项
- 重新赋值
app_memos触发响应式更新 - 触发保存操作
批量清除已完成:
app_clearCompleted(): void {
this.app_memos = this.app_memos.filter((app_item: App_MemoItem) => !app_item.app_completed);
this.app_saveMemos();
}
批量清除逻辑说明:
- 使用
filter方法保留app_completed为false的项 - 即过滤掉所有已完成的待办事项
- 触发保存操作
3.7 统计功能实现
统计功能为用户提供直观的数据概览,包括总数、待完成数、已完成数。
统计方法:
app_getStats(): { app_total: number; app_active: number; app_completed: number } {
const app_total: number = this.app_memos.length;
const app_completed: number = this.app_memos.filter((app_item: App_MemoItem) => app_item.app_completed).length;
return {
app_total,
app_active: app_total - app_completed,
app_completed
};
}
返回值类型说明:
app_total: 总待办数量app_active: 待完成数量 = 总数 - 已完成数app_completed: 已完成数量
统计栏UI:
if (this.app_memos.length > 0) {
Row({ space: 16 }) {
Text(`总数: ${this.app_getStats().app_total} | 待完成: ${this.app_getStats().app_active} | 已完成: ${this.app_getStats().app_completed}`)
.fontSize(14)
.fontColor($r('app.color.app_color_text_secondary'))
if (this.app_getStats().app_completed > 0) {
Button('清除已完成')
.width(120)
.height(36)
.fontSize(14)
.fontWeight(FontWeight.Medium)
.backgroundColor($r('app.color.app_color_warning'))
.fontColor($r('app.color.app_color_white'))
.borderRadius(6)
.onClick(() => this.app_clearCompleted())
}
}
.width('100%')
.padding({ left: 16, right: 16, bottom: 16 })
.justifyContent(FlexAlign.SpaceBetween)
}
统计栏UI特点:
- 使用条件渲染确保没有待办时不显示统计栏
- 统计信息使用管道符分隔显示
- "清除已完成"按钮仅在有已完成的待办时显示
- 按钮使用警告色(橙色)提示用户这是危险操作
3.8 生命周期与初始化
备忘录应用使用aboutToAppear生命周期回调进行数据初始化,这是ArkTS组件开发的标准模式。
aboutToAppear回调:
aboutToAppear(): void {
this.app_loadMemos();
}
生命周期说明:
aboutToAppear在组件即将显示时调用- 只会被调用一次,适合执行初始化操作
- 确保UI渲染前数据已经加载完成
四、组件结构解析
4.1 整体布局架构
备忘录应用的UI采用垂直布局(Column),整体结构如下:
build() {
Column() {
// 1. 标题栏
CommonTitleBar({
app_title: '备忘录',
app_showBack: true
})
// 2. 内容区域(Column + space: 16)
Column({ space: 16 }) {
// 输入区域
// 筛选按钮组
// 待办列表(Scroll包裹)
// 统计操作栏
}
.flexGrow(1)
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.app_color_background'))
}
布局层次说明:
| 层次 | 容器 | 作用 |
|---|---|---|
| 最外层 | Column | 页面根容器,设置背景色 |
| 第二层 | Column | 内容区域,子元素间距16 |
| 内容区 | Row | 输入行、筛选按钮组 |
| 内容区 | Scroll | 包裹列表,支持滚动 |
| 内容区 | Row | 底部统计操作栏 |
4.2 输入区域实现
Row({ space: 8 }) {
TextInput({ placeholder: '输入待办事项...', text: this.app_newMemo })
.width('flexGrow')
.height(48)
.fontSize(16)
.backgroundColor($r('app.color.app_color_white'))
.borderRadius(8)
.padding({ left: 16 })
.onChange((app_value: string) => {
this.app_newMemo = app_value;
})
.onSubmit(() => this.app_addMemo())
Button('添加')
.width(80)
.height(48)
.fontSize(16)
.fontWeight(FontWeight.Medium)
.backgroundColor($r('app.color.app_color_primary'))
.fontColor($r('app.color.app_color_white'))
.borderRadius(8)
.onClick(() => this.app_addMemo())
}
.width('100%')
.padding({ left: 16, right: 16 })
TextField配置说明:
| 属性 | 值 | 说明 |
|---|---|---|
| placeholder | ‘输入待办事项…’ | 占位提示文字 |
| text | this.app_newMemo | 双向绑定输入值 |
| height | 48 | 固定高度 |
| borderRadius | 8 | 圆角8 |
| onChange | 箭头函数 | 输入值变化时更新状态 |
| onSubmit | this.app_addMemo | 回车键提交 |
五、通用组件复用
5.1 CommonTitleBar组件
备忘录应用使用了CommonTitleBar通用标题栏组件,展示了ArkTS中组件复用的开发模式。
@Component
export struct CommonTitleBar {
app_title: string = '';
app_showBack: boolean = true;
app_backCallback?: () => void;
build() {
Row() {
if (this.app_showBack) {
Button() {
Image($r('app.media.foreground'))
.width(24)
.height(24)
.fillColor($r('app.color.app_color_white'))
}
.width(44)
.height(44)
.backgroundColor($r('app.color.app_color_transparent'))
.onClick(() => {
if (this.app_backCallback !== undefined) {
this.app_backCallback();
} else {
AppRouter.app_back();
}
})
}
Text(this.app_title)
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontColor($r('app.color.app_color_white'))
.flexGrow(1)
.textAlign(TextAlign.Center)
Blank()
.width(44)
}
.width('100%')
.height(56)
.backgroundColor($r('app.color.app_color_primary'))
.padding({ left: 16, right: 16 })
}
}
组件属性说明:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| app_title | string | ‘’ | 标题文字 |
| app_showBack | boolean | true | 是否显示返回按钮 |
| app_backCallback | () => void | undefined | 自定义返回回调 |
布局结构:
- 返回按钮:固定44宽度,仅在showBack为true时显示
- 标题文字:flexGrow占满剩余空间,居中显示
- 空白占位:固定44宽度,平衡返回按钮侧的宽度
六、技术亮点总结
6.1 声明式UI开发范式
备忘录应用充分展示了HarmonyOS ArkUI声明式开发的优势:
- 状态驱动UI:通过@State装饰器实现数据与UI的自动绑定,数据变化自动触发UI更新
- 简洁的语法:相比传统命令式UI,声明式UI代码更简洁、更易维护
- 组件化思想:通过@Component装饰器实现组件复用,提高代码复用性
6.2 响应式数据管理
应用的状态管理方案简洁高效:
@State app_memos: App_MemoItem[] = [];
@State app_newMemo: string = '';
@State app_filter: 'all' | 'active' | 'completed' = 'all';
三个@State变量覆盖了应用的全部动态数据:
- 待办列表数据
- 输入框状态
- 筛选条件状态
6.3 数据持久化策略
采用 Preferences 本地存储方案:
- 同步读取、异步写入的策略保证性能和可靠性
- JSON序列化实现复杂对象的存储
- 完善的错误处理机制
6.4 筛选模式的优雅实现
使用联合类型和switch语句实现筛选功能:
@State app_filter: 'all' | 'active' | 'completed' = 'all';
app_getFilteredMemos(): App_MemoItem[] {
switch (this.app_filter) {
case 'active':
return this.app_memos.filter((app_item: App_MemoItem) => !app_item.app_completed);
case 'completed':
return this.app_memos.filter((app_item: App_MemoItem) => app_item.app_completed);
default:
return this.app_memos;
}
}
七、完整代码对照
7.1 Memo页面完整代码
以下是备忘录应用的完整代码,供读者对照参考:
import { CommonTitleBar } from '../../components/CommonTitleBar';
import { AppStorage } from '../../utils/storage';
interface App_MemoItem {
app_id: string;
app_content: string;
app_completed: boolean;
app_createdAt: string;
}
@Entry
@Component
struct Memo {
@State app_memos: App_MemoItem[] = [];
@State app_newMemo: string = '';
@State app_filter: 'all' | 'active' | 'completed' = 'all';
aboutToAppear(): void {
this.app_loadMemos();
}
app_loadMemos(): void {
const app_stored: string = app_getString('memo_items', '[]');
try {
this.app_memos = JSON.parse(app_stored);
} catch (error) {
this.app_memos = [];
}
}
app_saveMemos(): void {
app_setString('memo_items', JSON.stringify(this.app_memos));
}
app_addMemo(): void {
if (this.app_newMemo.trim() === '') {
return;
}
const app_newItem: App_MemoItem = {
app_id: Date.now().toString(),
app_content: this.app_newMemo.trim(),
app_completed: false,
app_createdAt: new Date().toLocaleString('zh-CN')
};
this.app_memos.unshift(app_newItem);
this.app_newMemo = '';
this.app_saveMemos();
}
app_toggleMemo(app_id: string): void {
const app_index: number = this.app_memos.findIndex((app_item: App_MemoItem) => app_item.app_id === app_id);
if (app_index !== -1) {
this.app_memos[app_index].app_completed = !this.app_memos[app_index].app_completed;
this.app_saveMemos();
}
}
app_deleteMemo(app_id: string): void {
this.app_memos = this.app_memos.filter((app_item: App_MemoItem) => app_item.app_id !== app_id);
this.app_saveMemos();
}
app_clearCompleted(): void {
this.app_memos = this.app_memos.filter((app_item: App_MemoItem) => !app_item.app_completed);
this.app_saveMemos();
}
app_getFilteredMemos(): App_MemoItem[] {
switch (this.app_filter) {
case 'active':
return this.app_memos.filter((app_item: App_MemoItem) => !app_item.app_completed);
case 'completed':
return this.app_memos.filter((app_item: App_MonoItem) => app_item.app_completed);
default:
return this.app_memos;
}
}
app_getStats(): { app_total: number; app_active: number; app_completed: number } {
const app_total: number = this.app_memos.length;
const app_completed: number = this.app_memos.filter((app_item: App_MemoItem) => app_item.app_completed).length;
return {
app_total,
app_active: app_total - app_completed,
app_completed
};
}
build() {
Column() {
CommonTitleBar({
app_title: '备忘录',
app_showBack: true
})
Column({ space: 16 }) {
Row({ space: 8 }) {
TextInput({ placeholder: '输入待办事项...', text: this.app_newMemo })
.width('flexGrow')
.height(48)
.fontSize(16)
.backgroundColor($r('app.color.app_color_white'))
.borderRadius(8)
.padding({ left: 16 })
.onChange((app_value: string) => {
this.app_newMemo = app_value;
})
.onSubmit(() => this.app_addMemo())
Button('添加')
.width(80)
.height(48)
.fontSize(16)
.fontWeight(FontWeight.Medium)
.backgroundColor($r('app.color.app_color_primary'))
.fontColor($r('app.color.app_color_white'))
.borderRadius(8)
.onClick(() => this.app_addMemo())
}
.width('100%')
.padding({ left: 16, right: 16 })
Row({ space: 8 }) {
Button('全部')
.width('33%')
.height(40)
.fontSize(14)
.fontWeight(FontWeight.Medium)
.backgroundColor(this.app_filter === 'all' ? $r('app.color.app_color_primary') : $r('app.color.app_color_white'))
.fontColor(this.app_filter === 'all' ? $r('app.color.app_color_white') : $r('app.color.app_color_text_primary'))
.borderRadius(8)
.onClick(() => this.app_filter = 'all')
Button('待完成')
.width('33%')
.height(40)
.fontSize(14)
.fontWeight(FontWeight.Medium)
.backgroundColor(this.app_filter === 'active' ? $r('app.color.app_color_primary') : $r('app.color.app_color_white'))
.fontColor(this.app_filter === 'active' ? $r('app.color.app_color_white') : $r('app.color.app_color_text_primary'))
.borderRadius(8)
.onClick(() => this.app_filter = 'active')
Button('已完成')
.width('33%')
.height(40)
.fontSize(14)
.fontWeight(FontWeight.Medium)
.backgroundColor(this.app_filter === 'completed' ? $r('app.color.app_color_primary') : $r('app.color.app_color_white'))
.fontColor(this.app_filter === 'completed' ? $r('app.color.app_color_white') : $r('app.color.app_color_text_primary'))
.borderRadius(8)
.onClick(() => this.app_filter = 'completed')
}
.width('100%')
.padding({ left: 16, right: 16 })
Scroll() {
Column({ space: 8 }) {
ForEach(this.app_getFilteredMemos(), (app_item: App_MemoItem) => {
Row({ space: 12 }) {
Checkbox()
.select(app_item.app_completed)
.selectedColor($r('app.color.app_color_success'))
.onChange(() => this.app_toggleMemo(app_item.app_id))
Text(app_item.app_content)
.width('flexGrow')
.fontSize(16)
.fontColor(app_item.app_completed ? $r('app.color.app_color_text_tertiary') : $r('app.color.app_color_text_primary'))
.decoration({ type: app_item.app_completed ? TextDecorationType.LineThrough : TextDecorationType.None })
Text(app_item.app_createdAt)
.fontSize(12)
.fontColor($r('app.color.app_color_text_tertiary'))
Button() {
Text('删除')
.fontSize(12)
}
.width(50)
.height(32)
.backgroundColor($r('app.color.app_color_danger'))
.fontColor($r('app.color.app_color_white'))
.borderRadius(6)
.onClick(() => this.app_deleteMemo(app_item.app_id))
}
.width('100%')
.height(56)
.backgroundColor($r('app.color.app_color_white'))
.borderRadius(8)
.padding({ left: 16, right: 16 })
.alignItems(VerticalAlign.Center)
})
if (this.app_getFilteredMemos().length === 0) {
Column({ space: 8 }) {
Text('暂无待办事项')
.fontSize(16)
.fontColor($r('app.color.app_color_text_tertiary'))
Text('点击上方添加新的待办')
.fontSize(14)
.fontColor($r('app.color.app_color_text_secondary'))
}
.width('100%')
.padding({ top: 60, bottom: 60 })
.alignItems(HorizontalAlign.Center)
}
}
.width('100%')
.padding({ left: 16, right: 16 })
}
.width('100%')
.flexGrow(1)
if (this.app_memos.length > 0) {
Row({ space: 16 }) {
Text(`总数: ${this.app_getStats().app_total} | 待完成: ${this.app_getStats().app_active} | 已完成: ${this.app_getStats().app_completed}`)
.fontSize(14)
.fontColor($r('app.color.app_color_text_secondary'))
if (this.app_getStats().app_completed > 0) {
Button('清除已完成')
.width(120)
.height(36)
.fontSize(14)
.fontWeight(FontWeight.Medium)
.backgroundColor($r('app.color.app_color_warning'))
.fontColor($r('app.color.app_color_white'))
.borderRadius(6)
.onClick(() => this.app_clearCompleted())
}
}
.width('100%')
.padding({ left: 16, right: 16, bottom: 16 })
.justifyContent(FlexAlign.SpaceBetween)
}
}
.width('100%')
.flexGrow(1)
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.app_color_background'))
}
}
八、开发要点回顾
8.1 ArkTS开发核心概念
- @State装饰器:组件级状态管理,只能访问和修改组件自身状态
- @Component装饰器:自定义UI组件的声明方式
- @Entry装饰器:标记页面的入口组件
- build()方法:组件的UI描述方法,返回组件树
8.2 数据流管理要点
- 单向数据流:数据变化自动驱动UI更新,无需手动操作DOM
- 响应式更新:ArkUI框架会追踪@State变量的使用,自动执行最小粒度更新
- 持久化时机:在状态变更后立即保存,保证数据一致性
8.3 常见操作模式
| 操作 | 实现方式 |
|---|---|
| 添加 | unshift添加到数组头部 |
| 删除 | filter过滤排除目标项 |
| 修改 | findIndex找到索引后修改 |
| 筛选 | filter根据条件过滤数组 |
| 统计 | reduce或filter计算数量 |
九、总结
备忘录应用虽然功能简单,但完整展示了HarmonyOS ArkUI开发的核心模式:
- interface定义数据结构:清晰建模待办事项
- @State管理响应式状态:简洁高效的状态管理方案
- ForEach渲染动态列表:声明式列表渲染范式
- AppStorage持久化数据:可靠的本地存储方案
- 组件化设计:CommonTitleBar的复用展示组件化思想
这些核心模式是开发复杂HarmonyOS应用的基础,掌握好备忘录应用的开发模式,能够帮助开发者快速上手HarmonyOS应用开发。
更多推荐



所有评论(0)