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 实现任务完成标记;
  • 支持任务优先级设置(高/中/低);
  • 支持设置截止日期;
  • 实现任务添加功能;
  • 实现任务删除功能;
  • 支持按状态筛选任务(全部/进行中/已完成);
  • 统计今日待办数量;
  • 统计已完成任务数量;
  • 计算完成进度百分比;
  • 使用 ListForEach 渲染任务列表;
  • 使用空状态提示优化无任务页面;
  • 使用 @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 文件中更方便理解。

如果后续继续扩展,可以考虑把任务输入组件、任务项组件、筛选按钮和统计卡片拆分成独立组件。

六、核心实现思路

本项目的核心流程如下:

  1. 定义任务数据结构;
  2. 使用 @State 保存输入内容、选中的优先级、筛选条件和任务列表;
  3. 用户输入任务内容;
  4. 用户选择任务优先级;
  5. 点击添加按钮创建新任务;
  6. 使用数组保存所有任务;
  7. 根据筛选条件展示不同任务;
  8. 使用 ForEach 渲染任务列表;
  9. 点击复选框切换任务完成状态;
  10. 点击删除按钮删除指定任务;
  11. 点击清空已完成按钮清除所有已完成任务;
  12. 顶部统计卡片根据任务数据自动更新;
  13. 进度条显示整体完成进度;
  14. 没有任务时显示空状态提示。

项目中最重要的状态变量如下:

@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. 任务筛选功能

筛选通过 filterTypegetFilteredTasks 方法实现:

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. 打开应用,检查页面是否正常显示预置的示例任务;
  2. 检查统计卡片是否显示正确的待办数、已完成数和完成率;
  3. 检查进度条是否显示正确的完成进度;
  4. 在输入框中输入新任务内容;
  5. 选择不同的优先级,检查优先级按钮颜色是否变化;
  6. 点击"添加任务"按钮,检查新任务是否出现在列表顶部;
  7. 检查统计数据是否更新;
  8. 点击任务前的复选框,检查任务是否标记为已完成(文字划线变灰);
  9. 检查统计数据和进度条是否更新;
  10. 点击"进行中"筛选,检查是否只显示未完成任务;
  11. 点击"已完成"筛选,检查是否只显示已完成任务;
  12. 点击任务的"删除"按钮,检查任务是否被删除;
  13. 点击"清除已完成"按钮,检查所有已完成任务是否被清除;
  14. 删除所有任务,检查空状态提示是否显示。

测试结果如下:

测试功能测试结果
页面正常显示成功
任务输入成功
优先级选择成功
添加任务成功
标记完成成功
删除任务成功
清除已完成成功
任务筛选成功
统计数据更新成功
进度条更新成功
空状态提示成功

经过测试,应用主要功能可以正常运行,任务状态和页面数据都能根据用户操作及时更新。

十、开发中遇到的问题

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 实现任务完成标记;
  • 使用 mapfilter 操作任务数组;
  • 支持高/中/低三级优先级;
  • 实现任务添加和删除功能;
  • 支持按状态筛选任务;
  • 动态计算待办数、已完成数和完成率;
  • 使用 Progress 组件显示完成进度;
  • 使用 ListForEach 渲染任务列表;
  • 使用条件渲染显示空状态和清除按钮;
  • 使用 @Builder 封装页面局部结构;
  • 完成一个可以运行的 HarmonyOS 任务管理工具页面。

这个项目虽然是一个单页面练习,但它完整实现了待办清单的核心功能。它展示了 ArkTS 中表单交互、数组操作、状态管理和数据统计的基本方法。

后续可以在这个基础上继续扩展,例如:

  • 增加本地数据持久化;
  • 增加任务分类和标签;
  • 增加提醒通知功能;
  • 增加子任务功能;
  • 增加任务搜索功能;
  • 增加任务编辑功能;
  • 增加截止日期选择器;
  • 增加数据统计图表;
  • 增加深色模式适配;
  • 增加任务拖拽排序。

整体来看,待办清单应用适合作为 HarmonyOS ArkTS 的练习项目。它功能实用、交互经典,也能体现 ArkUI 声明式开发和状态驱动页面刷新的基本思想。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐