HarmonyOS ArkTS 实战:实现一个高效待办清单应用
HarmonyOS ArkTS 实战:实现一个高效待办清单应用
项目效果
本文实现的是一个基于 HarmonyOS 和 ArkTS 的高效待办清单应用。项目中使用 ArkUI 组件完成页面布局,通过 @State 管理状态数据,实现任务添加、任务完成标记、任务删除、任务分类、优先级设置、截止日期、任务筛选、完成统计和数据清空等功能。
最终运行效果如下:
页面主要包含以下内容:
- 顶部应用标题和今日统计;
- 任务输入框和添加按钮;
- 任务分类筛选(全部/进行中/已完成);
- 任务优先级标签;
- 截止日期显示;
- 任务完成复选框;
- 任务删除按钮;
- 完成进度统计;
- 空状态提示;
- 页面整体采用 ArkUI 声明式布局。
本文重点是演示如何在 HarmonyOS 项目中使用 ArkTS 和 ArkUI 实现一个实用的任务管理类单页面应用。项目代码主要写在 entry/src/main/ets/pages/Index.ets 文件中,适合作为 HarmonyOS ArkTS 入门到进阶之间的练习案例。
前言
在日常工作和生活中,我们每天都有很多事情需要处理。一个好用的待办清单可以帮助我们理清思路,合理安排时间,提高工作效率。传统的待办应用往往功能臃肿,而我们需要一个简洁高效的工具来管理日常任务。
从应用开发角度来看,这个项目不依赖后端接口,也不需要数据库,但能练习 ArkTS 中的状态管理、输入框绑定、复选框交互、列表渲染、条件筛选、数组操作和条件渲染等内容。
本文基于 HarmonyOS 和 ArkTS 实现一个高效待办清单应用。用户可以添加新任务,设置优先级和截止日期,标记任务完成状态,按状态筛选任务,删除不需要的任务,查看完成进度统计。
这个项目的核心不是简单的任务列表,而是完整的任务管理流程。每一次添加、完成、删除和筛选任务,本质上都是对任务数组的操作。状态变化后,页面会自动刷新,这正是 ArkUI 声明式开发的基本思想。
一、项目目标
本次实践主要实现以下目标:
- 创建 HarmonyOS ArkTS 页面;
- 使用
@Entry和@Component定义页面组件; - 使用
@State管理页面状态; - 使用
TextInput接收任务输入; - 使用
Checkbox实现任务完成标记; - 支持任务优先级设置(高/中/低);
- 支持设置截止日期;
- 实现任务添加功能;
- 实现任务删除功能;
- 支持按状态筛选任务(全部/进行中/已完成);
- 统计今日待办数量;
- 统计已完成任务数量;
- 计算完成进度百分比;
- 使用
List和ForEach渲染任务列表; - 使用空状态提示优化无任务页面;
- 使用
@Builder封装统计卡片、任务项和筛选按钮; - 完成一个可以运行的待办清单页面。
这个项目虽然是单页面应用,但它有完整的任务添加、编辑、完成、删除和筛选流程,比普通静态页面更适合练习 ArkTS。
二、技术栈
| 类型 | 内容 |
|---|---|
| 开发方向 | HarmonyOS 应用开发 |
| 开发语言 | ArkTS |
| UI 框架 | ArkUI |
| SDK 版本 | HarmonyOS API 23 及以上 |
| 工程模型 | Stage 模型 |
| 核心组件 | Text / TextInput / Button / Checkbox / Column / Row / List / ForEach / Progress |
| 状态管理 | @State |
| 数据处理 | 数组操作 / filter / map / 进度计算 |
| 项目入口 | entry/src/main/ets/pages/Index.ets |
| 运行平台 | 模拟器或真机 |
本项目是 HarmonyOS 原生 ArkTS 项目。页面主体由 ArkUI 组件构建,核心逻辑写在 Index.ets 文件中,不依赖后端接口,也不需要额外配置数据库。
三、为什么选择待办清单项目
高效待办清单应用适合作为 ArkTS 练习项目,主要有以下几个原因。
第一,实用性强。待办清单是每个人都会用到的工具,一个简洁好用的待办应用可以直接应用于日常工作和生活。
第二,业务场景真实。无论是职场人士还是学生,都需要管理自己的任务,待办清单是最基础也是最常用的效率工具。
第三,适合练习状态管理。任务内容、筛选条件、任务列表、选中的优先级都属于页面状态。状态变化后,页面会自动刷新。
第四,适合练习数组处理。每个任务都是数组中的一个对象。添加任务就是向数组中插入对象,删除任务就是过滤数组,标记完成就是修改数组元素属性,筛选任务就是按条件返回新的数组。
第五,适合练习表单交互。任务输入、优先级选择、日期选择都是常见的表单交互形式,掌握这些可以应用到很多其他应用中。
第六,扩展空间比较大。基础功能完成后,可以继续增加本地存储、任务分类、提醒功能、子任务、任务搜索和数据统计图表。
在本项目中,tasks 是核心数据源。页面中的统计数据、任务列表和筛选结果都由它计算或渲染得到。
四、功能规则说明
本文中的任务优先级分为三级:
| 优先级 | 颜色 | 含义 |
|---|---|---|
| 高 | #EF4444 | 紧急重要,需要优先处理 |
| 中 | #F59E0B | 重要不紧急,安排时间处理 |
| 低 | #10B981 | 不重要不紧急,有空再处理 |
任务状态分为两类:
| 状态 | 显示样式 |
|---|---|
| 进行中 | 正常显示,复选框未选中 |
| 已完成 | 文字划线,灰色显示,复选框选中 |
筛选规则如下:
全部:显示所有任务
进行中:只显示未完成的任务
已完成:只显示已完成的任务
统计规则如下:
今日待办 = 所有未完成任务数量
已完成 = 所有已完成任务数量
完成率 = 已完成任务数 / 总任务数 * 100%
每次添加、完成或删除任务后,统计数据都会自动更新。
五、项目结构
本项目主要修改首页文件:
entry
└── src
└── main
└── ets
└── pages
└── Index.ets
其中:
| 文件 | 作用 |
|---|---|
| Index.ets | 编写页面结构、状态数据和待办任务管理逻辑 |
本文不涉及复杂路由,也不需要额外创建多个页面。对于练习项目来说,把主要逻辑集中在一个 Index.ets 文件中更方便理解。
如果后续继续扩展,可以考虑把任务输入组件、任务项组件、筛选按钮和统计卡片拆分成独立组件。
六、核心实现思路
本项目的核心流程如下:
- 定义任务数据结构;
- 使用
@State保存输入内容、选中的优先级、筛选条件和任务列表; - 用户输入任务内容;
- 用户选择任务优先级;
- 点击添加按钮创建新任务;
- 使用数组保存所有任务;
- 根据筛选条件展示不同任务;
- 使用
ForEach渲染任务列表; - 点击复选框切换任务完成状态;
- 点击删除按钮删除指定任务;
- 点击清空已完成按钮清除所有已完成任务;
- 顶部统计卡片根据任务数据自动更新;
- 进度条显示整体完成进度;
- 没有任务时显示空状态提示。
项目中最重要的状态变量如下:
@State inputText: string = ''
@State selectedPriority: string = '中'
@State filterType: string = '全部'
@State tasks: TodoTask[] = []
@State nextId: number = 1
其中:
| 状态变量 | 作用 |
|---|---|
| inputText | 任务输入框内容 |
| selectedPriority | 当前选中的优先级 |
| filterType | 当前筛选条件 |
| tasks | 任务数组 |
| nextId | 生成任务唯一编号 |
tasks 是本项目中最重要的数据。所有任务展示、筛选和统计都依赖这个数组。
七、Index.ets 完整代码
打开文件:
entry/src/main/ets/pages/Index.ets
将其中内容替换为下面代码:
interface TodoTask {
id: number
content: string
priority: string
completed: boolean
createTime: string
dueDate: string
}
@Entry
@Component
struct Index {
@State inputText: string = ''
@State selectedPriority: string = '中'
@State filterType: string = '全部'
@State nextId: number = 5
@State tasks: TodoTask[] = [
{
id: 1,
content: '完成项目需求文档编写',
priority: '高',
completed: false,
createTime: '09:00',
dueDate: '今天'
},
{
id: 2,
content: '参加部门周会',
priority: '中',
completed: true,
createTime: '08:30',
dueDate: '今天'
},
{
id: 3,
content: '回复客户邮件',
priority: '高',
completed: false,
createTime: '10:15',
dueDate: '今天'
},
{
id: 4,
content: '整理上周工作周报',
priority: '低',
completed: false,
createTime: '11:00',
dueDate: '明天'
}
]
private addTask(): void {
let content = this.inputText.trim()
if (content.length === 0) {
return
}
let task: TodoTask = {
id: this.nextId,
content: content,
priority: this.selectedPriority,
completed: false,
createTime: this.getCurrentTime(),
dueDate: '今天'
}
this.tasks = [task, ...this.tasks]
this.nextId++
this.inputText = ''
}
private toggleTask(id: number): void {
this.tasks = this.tasks.map((task: TodoTask) => {
if (task.id === id) {
return { ...task, completed: !task.completed }
}
return task
})
}
private deleteTask(id: number): void {
this.tasks = this.tasks.filter((task: TodoTask) => task.id !== id)
}
private clearCompleted(): void {
this.tasks = this.tasks.filter((task: TodoTask) => !task.completed)
}
private getFilteredTasks(): TodoTask[] {
if (this.filterType === '进行中') {
return this.tasks.filter((task: TodoTask) => !task.completed)
}
if (this.filterType === '已完成') {
return this.tasks.filter((task: TodoTask) => task.completed)
}
return this.tasks
}
private getPendingCount(): number {
return this.tasks.filter((task: TodoTask) => !task.completed).length
}
private getCompletedCount(): number {
return this.tasks.filter((task: TodoTask) => task.completed).length
}
private getCompletionRate(): number {
if (this.tasks.length === 0) {
return 0
}
return Math.round((this.getCompletedCount() / this.tasks.length) * 100)
}
private getCurrentTime(): string {
let date = new Date()
return `${this.formatTwo(date.getHours())}:${this.formatTwo(date.getMinutes())}`
}
private formatTwo(value: number): string {
return value < 10 ? '0' + value.toString() : value.toString()
}
private getPriorityColor(priority: string): string {
const colors: Record<string, string> = {
'高': '#EF4444',
'中': '#F59E0B',
'低': '#10B981'
}
return colors[priority] || '#6B7280'
}
@Builder
StatCard(title: string, value: string, color: string) {
Column() {
Text(value)
.fontSize(24)
.fontWeight(FontWeight.Bold)
.fontColor(color)
Text(title)
.fontSize(13)
.fontColor('#6B7280')
.margin({ top: 4 })
}
.width('31%')
.height(80)
.justifyContent(FlexAlign.Center)
.backgroundColor(Color.White)
.borderRadius(16)
.shadow({
radius: 10,
color: '#12000000',
offsetX: 0,
offsetY: 4
})
}
@Builder
PriorityButton(text: string) {
Button(text)
.height(34)
.padding({ left: 16, right: 16 })
.fontSize(13)
.fontColor(this.selectedPriority === text ? Color.White : '#4B5563')
.backgroundColor(this.selectedPriority === text ? this.getPriorityColor(text) : '#F3F4F6')
.borderRadius(17)
.onClick(() => {
this.selectedPriority = text
})
}
@Builder
FilterButton(text: string) {
Button(text)
.height(36)
.layoutWeight(1)
.fontSize(14)
.fontColor(this.filterType === text ? Color.White : '#4B5563')
.backgroundColor(this.filterType === text ? '#0A59F7' : '#F3F4F6')
.borderRadius(18)
.onClick(() => {
this.filterType = text
})
}
@Builder
TaskItem(task: TodoTask) {
Row() {
Checkbox({ name: task.id.toString(), group: 'tasks' })
.select(task.completed)
.width(24)
.height(24)
.selectedColor('#0A59F7')
.onChange((value: boolean) => {
this.toggleTask(task.id)
})
Column() {
Text(task.content)
.fontSize(16)
.fontColor(task.completed ? '#9CA3AF' : '#182431')
.decoration({ type: task.completed ? TextDecorationType.LineThrough : TextDecorationType.None })
.maxLines(2)
.textOverflow({ overflow: TextOverflow.Ellipsis })
Row() {
Text(task.priority)
.fontSize(11)
.fontColor(Color.White)
.backgroundColor(this.getPriorityColor(task.priority))
.padding({ left: 6, right: 6, top: 2, bottom: 2 })
.borderRadius(4)
Text(`截止:${task.dueDate}`)
.fontSize(12)
.fontColor('#9CA3AF')
.margin({ left: 8 })
Text(`创建:${task.createTime}`)
.fontSize(12)
.fontColor('#9CA3AF')
.margin({ left: 8 })
}
.margin({ top: 8 })
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
.margin({ left: 12, right: 12 })
Button('删除')
.height(32)
.fontSize(12)
.fontColor('#EF4444')
.backgroundColor('#FEF2F2')
.borderRadius(14)
.onClick(() => {
this.deleteTask(task.id)
})
}
.width('100%')
.padding(14)
.margin({ bottom: 10 })
.backgroundColor(Color.White)
.borderRadius(12)
.shadow({
radius: 6,
color: '#08000000',
offsetX: 0,
offsetY: 2
})
}
build() {
Column() {
Text('待办清单')
.fontSize(28)
.fontWeight(FontWeight.Bold)
.fontColor('#182431')
.margin({ top: 22 })
Text('基于 HarmonyOS ArkTS 的任务管理工具')
.fontSize(14)
.fontColor('#6B7280')
.margin({ top: 8, bottom: 20 })
Row() {
this.StatCard('今日待办', `${this.getPendingCount()}`, '#0A59F7')
this.StatCard('已完成', `${this.getCompletedCount()}`, '#10B981')
this.StatCard('完成率', `${this.getCompletionRate()}%`, '#F59E0B')
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
.margin({ bottom: 16 })
Column() {
Progress({ value: this.getCompletionRate(), total: 100, type: ProgressType.Linear })
.width('100%')
.height(8)
.color('#0A59F7')
.backgroundColor('#E5E7EB')
.borderRadius(4)
.margin({ bottom: 8 })
Text(`今日任务完成进度:${this.getCompletionRate()}%`)
.fontSize(13)
.fontColor('#6B7280')
}
.width('100%')
.padding(16)
.backgroundColor(Color.White)
.borderRadius(16)
.margin({ bottom: 16 })
.shadow({
radius: 8,
color: '#08000000',
offsetX: 0,
offsetY: 2
})
Column() {
Text('添加新任务')
.fontSize(16)
.fontWeight(FontWeight.Medium)
.fontColor('#182431')
.width('100%')
.margin({ bottom: 12 })
TextInput({
placeholder: '输入任务内容...',
text: this.inputText
})
.height(44)
.fontSize(15)
.backgroundColor('#F5F7FA')
.borderRadius(12)
.padding({ left: 12, right: 12 })
.margin({ bottom: 12 })
.onChange((value: string) => {
this.inputText = value
})
Text('优先级')
.fontSize(13)
.fontColor('#6B7280')
.width('100%')
.margin({ bottom: 8 })
Row() {
this.PriorityButton('高')
Blank().width(8)
this.PriorityButton('中')
Blank().width(8)
this.PriorityButton('低')
}
.width('100%')
.margin({ bottom: 12 })
Button('添加任务')
.height(44)
.fontSize(16)
.fontColor(Color.White)
.backgroundColor('#0A59F7')
.borderRadius(12)
.width('100%')
.onClick(() => {
this.addTask()
})
}
.width('100%')
.padding(16)
.backgroundColor(Color.White)
.borderRadius(16)
.margin({ bottom: 16 })
.shadow({
radius: 8,
color: '#08000000',
offsetX: 0,
offsetY: 2
})
Row() {
Text('任务列表')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.fontColor('#182431')
Blank()
if (this.getCompletedCount() > 0) {
Button('清除已完成')
.height(32)
.fontSize(13)
.fontColor('#EF4444')
.backgroundColor('#FEF2F2')
.borderRadius(14)
.onClick(() => {
this.clearCompleted()
})
}
}
.width('100%')
.margin({ bottom: 12 })
Row() {
this.FilterButton('全部')
Blank().width(8)
this.FilterButton('进行中')
Blank().width(8)
this.FilterButton('已完成')
}
.width('100%')
.margin({ bottom: 12 })
if (this.getFilteredTasks().length === 0) {
Column() {
Text('暂无任务')
.fontSize(16)
.fontColor('#6B7280')
Text('添加新任务,开始高效的一天吧')
.fontSize(13)
.fontColor('#9CA3AF')
.margin({ top: 8 })
}
.width('100%')
.padding(30)
.backgroundColor(Color.White)
.borderRadius(16)
} else {
List() {
ForEach(this.getFilteredTasks(), (task: TodoTask) => {
ListItem() {
this.TaskItem(task)
}
}, (task: TodoTask) => task.id.toString())
}
.width('100%')
.layoutWeight(1)
.scrollBar(BarState.Off)
}
}
.width('100%')
.height('100%')
.padding({ left: 18, right: 18 })
.backgroundColor('#F5F7FA')
}
}
八、代码实现说明
1. 定义任务数据结构
项目中使用 TodoTask 接口描述每一个任务:
interface TodoTask {
id: number
content: string
priority: string
completed: boolean
createTime: string
dueDate: string
}
字段说明如下:
| 字段 | 作用 |
|---|---|
| id | 任务唯一编号 |
| content | 任务内容 |
| priority | 任务优先级 |
| completed | 是否已完成 |
| createTime | 创建时间 |
| dueDate | 截止日期 |
其中 id 用于区分不同任务,completed 用于标记任务状态,priority 用于显示优先级标签。
2. 使用 @State 管理页面状态
本项目中使用多个状态变量:
@State inputText: string = ''
@State selectedPriority: string = '中'
@State filterType: string = '全部'
@State tasks: TodoTask[] = []
@State nextId: number = 1
这些状态变量分别保存输入内容、选中的优先级、筛选条件和任务列表。当用户输入任务、选择优先级、添加任务或标记完成时,状态数据都会发生变化。ArkUI 会根据最新状态自动刷新页面。
3. 添加新任务
添加任务通过 addTask 方法实现:
private addTask(): void {
let content = this.inputText.trim()
if (content.length === 0) {
return
}
let task: TodoTask = {
id: this.nextId,
content: content,
priority: this.selectedPriority,
completed: false,
createTime: this.getCurrentTime(),
dueDate: '今天'
}
this.tasks = [task, ...this.tasks]
this.nextId++
this.inputText = ''
}
如果输入内容为空则不添加任务。新任务会放在数组最前面,方便用户优先看到最新添加的任务。添加完成后清空输入框。
4. 切换任务完成状态
点击复选框时切换任务完成状态:
private toggleTask(id: number): void {
this.tasks = this.tasks.map((task: TodoTask) => {
if (task.id === id) {
return { ...task, completed: !task.completed }
}
return task
})
}
这里使用 map 方法遍历数组,找到对应id的任务并反转其 completed 属性。使用展开运算符创建新对象,保证状态变化能被检测到。
5. 任务筛选功能
筛选通过 filterType 和 getFilteredTasks 方法实现:
private getFilteredTasks(): TodoTask[] {
if (this.filterType === '进行中') {
return this.tasks.filter((task: TodoTask) => !task.completed)
}
if (this.filterType === '已完成') {
return this.tasks.filter((task: TodoTask) => task.completed)
}
return this.tasks
}
筛选不会改变原始数组,只会改变当前页面展示内容。这样切换筛选条件时不会丢失任务数据。
6. 删除任务功能
删除任务通过 deleteTask 方法实现:
private deleteTask(id: number): void {
this.tasks = this.tasks.filter((task: TodoTask) => task.id !== id)
}
这里使用 id 删除任务,而不是使用任务内容。因为多个任务可能有相同内容,使用唯一编号更安全。
7. 清除已完成任务
一键清除所有已完成的任务:
private clearCompleted(): void {
this.tasks = this.tasks.filter((task: TodoTask) => !task.completed)
}
这个功能可以帮助用户快速清理已完成的任务,保持列表整洁。
8. 统计数据计算
待办数量、已完成数量和完成率都通过数组方法动态计算:
private getPendingCount(): number {
return this.tasks.filter((task: TodoTask) => !task.completed).length
}
private getCompletedCount(): number {
return this.tasks.filter((task: TodoTask) => task.completed).length
}
private getCompletionRate(): number {
if (this.tasks.length === 0) {
return 0
}
return Math.round((this.getCompletedCount() / this.tasks.length) * 100)
}
这样可以保证统计数据始终与任务数组保持一致,不需要额外维护计数变量。
9. 进度条显示
使用 Progress 组件显示完成进度:
Progress({ value: this.getCompletionRate(), total: 100, type: ProgressType.Linear })
.width('100%')
.height(8)
.color('#0A59F7')
.backgroundColor('#E5E7EB')
.borderRadius(4)
进度条的值绑定到完成率,任务状态变化时进度条会自动更新。
九、运行项目
代码编写完成后,在 DevEco Studio 中选择模拟器或真机运行项目。
运行成功后,页面会显示"待办清单"。用户可以输入任务内容,选择优先级,添加新任务,标记任务完成,删除任务,筛选查看不同状态的任务。
可以按照以下步骤进行测试:
- 打开应用,检查页面是否正常显示预置的示例任务;
- 检查统计卡片是否显示正确的待办数、已完成数和完成率;
- 检查进度条是否显示正确的完成进度;
- 在输入框中输入新任务内容;
- 选择不同的优先级,检查优先级按钮颜色是否变化;
- 点击"添加任务"按钮,检查新任务是否出现在列表顶部;
- 检查统计数据是否更新;
- 点击任务前的复选框,检查任务是否标记为已完成(文字划线变灰);
- 检查统计数据和进度条是否更新;
- 点击"进行中"筛选,检查是否只显示未完成任务;
- 点击"已完成"筛选,检查是否只显示已完成任务;
- 点击任务的"删除"按钮,检查任务是否被删除;
- 点击"清除已完成"按钮,检查所有已完成任务是否被清除;
- 删除所有任务,检查空状态提示是否显示。
测试结果如下:
| 测试功能 | 测试结果 |
|---|---|
| 页面正常显示 | 成功 |
| 任务输入 | 成功 |
| 优先级选择 | 成功 |
| 添加任务 | 成功 |
| 标记完成 | 成功 |
| 删除任务 | 成功 |
| 清除已完成 | 成功 |
| 任务筛选 | 成功 |
| 统计数据更新 | 成功 |
| 进度条更新 | 成功 |
| 空状态提示 | 成功 |
经过测试,应用主要功能可以正常运行,任务状态和页面数据都能根据用户操作及时更新。
十、开发中遇到的问题
1. 空输入处理
如果用户不输入内容就点击添加,会创建空任务。因此在 addTask 方法中判断内容是否为空:
if (content.length === 0) {
return
}
2. 状态更新检测
直接修改数组元素的属性可能无法触发UI更新,因此使用 map 方法返回新数组:
this.tasks = this.tasks.map((task: TodoTask) => {
if (task.id === id) {
return { ...task, completed: !task.completed }
}
return task
})
3. 完成率除以零问题
当没有任务时,计算完成率会出现除以零的情况,因此需要特殊处理:
if (this.tasks.length === 0) {
return 0
}
4. 已完成任务样式
已完成的任务需要有明显的视觉区分,使用文字划线和灰色:
.fontColor(task.completed ? '#9CA3AF' : '#182431')
.decoration({ type: task.completed ? TextDecorationType.LineThrough : TextDecorationType.None })
5. 清除按钮显示控制
只有当存在已完成任务时才显示"清除已完成"按钮,避免按钮一直显示造成困扰:
if (this.getCompletedCount() > 0) {
Button('清除已完成')
// ...
}
十一、总结
本文基于 HarmonyOS 和 ArkTS 实现了一个高效待办清单应用。项目通过 @State 管理页面数据,使用 ArkUI 组件完成页面布局,并实现了任务添加、完成标记、优先级设置、任务筛选、删除任务和进度统计等功能。
通过本次实践,主要完成了以下内容:
- 使用
@Entry和@Component创建页面组件; - 使用
@State保存输入内容、优先级、筛选条件和任务列表; - 使用
TextInput获取任务输入; - 使用
Checkbox实现任务完成标记; - 使用
map和filter操作任务数组; - 支持高/中/低三级优先级;
- 实现任务添加和删除功能;
- 支持按状态筛选任务;
- 动态计算待办数、已完成数和完成率;
- 使用
Progress组件显示完成进度; - 使用
List和ForEach渲染任务列表; - 使用条件渲染显示空状态和清除按钮;
- 使用
@Builder封装页面局部结构; - 完成一个可以运行的 HarmonyOS 任务管理工具页面。
这个项目虽然是一个单页面练习,但它完整实现了待办清单的核心功能。它展示了 ArkTS 中表单交互、数组操作、状态管理和数据统计的基本方法。
后续可以在这个基础上继续扩展,例如:
- 增加本地数据持久化;
- 增加任务分类和标签;
- 增加提醒通知功能;
- 增加子任务功能;
- 增加任务搜索功能;
- 增加任务编辑功能;
- 增加截止日期选择器;
- 增加数据统计图表;
- 增加深色模式适配;
- 增加任务拖拽排序。
整体来看,待办清单应用适合作为 HarmonyOS ArkTS 的练习项目。它功能实用、交互经典,也能体现 ArkUI 声明式开发和状态驱动页面刷新的基本思想。
更多推荐



所有评论(0)