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、测试、元服务和应用上架分发等。

更多推荐