鸿蒙购物清单 - 列表增删改查 清单记录工具


1. 应用概述
购物清单(ShoppingList)是一款基于HarmonyOS ArkTS框架开发的日常生活工具,其核心功能是帮助用户记录购物清单,支持添加物品、标记完成、删除物品等操作。这款应用是五个应用中最复杂的一个,引入了List列表组件、ForEach循环渲染、Checkbox复选框、数组状态管理以及删除操作等进阶特性。
从技术实现角度来看,购物清单应用充分利用了ArkUI框架的列表渲染能力。通过@State装饰器管理购物物品数组,通过ForEach组件实现列表渲染,通过Checkbox组件实现完成状态切换,通过splice方法实现删除操作。应用的代码结构清晰地展示了列表类应用的核心开发模式。
本技术博客将从应用架构设计、核心代码实现、列表渲染机制、状态管理设计、数组操作方法、UI交互设计等多个维度,对这款购物清单应用进行全面的技术剖析。通过本文的深入讲解,读者能够掌握HarmonyOS ArkTS开发中的核心知识点,特别是List列表组件的使用、ForEach循环渲染、数组状态管理、Checkbox组件交互以及待办事项类应用的设计要点。
2. 技术架构分析
2.1 整体架构设计
购物清单应用采用了标准的单页面架构,整个应用仅包含一个主页面,通过垂直布局的Column容器组织各个功能区块。从代码组织角度来看,应用主要分为以下几个核心部分:页面入口组件(ShoppingList)、通用标题栏组件(CommonTitleBar)、输入区域、统计区域、购物清单列表区域。
┌─────────────────────────────────────────────────────────┐
│ ShoppingList页面 │
│ ┌─────────────────────────────────────────────────┐ │
│ │ CommonTitleBar组件 │ │
│ │ (导航栏+标题显示) │ │
│ └─────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 输入区域 │ │
│ │ (TextInput + Button) │ │
│ └─────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 统计区域 │ │
│ │ (待购买/已完成统计) │ │
│ └─────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 购物清单列表区域 │ │
│ │ (List + ForEach + Checkbox) │ │
│ └─────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
购物清单应用是五个应用中UI结构最复杂的一个,包含了输入控件、统计显示和动态列表三个功能区块。
2.2 模块依赖关系
从依赖关系的角度分析,购物清单应用主要依赖以下几个核心模块:
首先是CommonTitleBar组件,该组件提供了统一的页面标题栏和返回按钮功能。
其次是ArkUI的基础组件:
- TextInput:文本输入组件,用于输入新物品名称
- Button:按钮组件,用于触发添加操作
- List:列表容器组件,用于展示物品列表
- ListItem:列表项组件,对应单个物品
- ForEach:循环渲染组件,用于渲染物品列表
- Checkbox:复选框组件,用于标记物品完成状态
- Row/Column:布局容器组件
2.3 数据模型设计
购物清单应用的数据模型设计了一个物品数组:
@State app_items: Record<string, boolean>[] = [];
@State app_newItem: string = '';
| 状态变量 | 类型 | 初始值 | 说明 |
|---|---|---|---|
| app_items | Record<string, boolean>[] | [] | 购物物品数组 |
| app_newItem | string | ‘’ | 新物品输入框的值 |
物品的数据结构采用Record类型:
Record<string, boolean> = {
'name': '物品名称', // string
'checked': false // boolean
}
使用Record类型而非自定义接口是ArkTS中的常见做法。Record<string, boolean>表示键为string类型、值为boolean类型的对象。
3. 核心代码详解
3.1 状态管理机制
购物清单应用的状态管理使用数组和字符串两个@State装饰器:
@State app_items: Record<string, boolean>[] = [];
@State app_newItem: string = '';
两个状态变量的职责划分:
app_items:存储购物清单中的所有物品,每个物品包含名称和完成状态
app_newItem:存储用户当前在输入框中输入的文本
数组状态的特点:
- 数组是引用类型,修改数组元素需要触发状态更新
- 直接修改数组元素(如
this.app_items[0].checked = true)不会自动触发UI更新 - 需要使用数组方法(push、splice)来修改数组
3.2 添加物品功能
添加物品功能展示了如何向数组添加元素:
Button('添加')
.width('30%')
.onClick(() => {
if (this.app_newItem !== '') {
let app_item: Record<string, boolean> = {
'name': this.app_newItem,
'checked': false
};
this.app_items.push(app_item);
this.app_newItem = '';
}
})
添加物品的流程:
- 检查输入是否为空
- 创建新的物品对象(名称=输入值,完成状态=false)
- 使用push方法将物品添加到数组
- 清空输入框
push方法的特点:
- 直接修改原数组
- 自动触发状态更新
- UI自动重新渲染
3.3 列表渲染机制
ForEach组件是ArkUI中渲染列表的核心组件:
List() {
ForEach(this.app_items, (app_item: Record<string, boolean>, app_index: number) => {
ListItem() {
Row() {
Checkbox()
.select(app_item['checked'])
.onChange((app_value: boolean) => {
this.app_items[app_index]['checked'] = app_value;
})
Text(app_item['name'])
.fontSize(16)
.fontColor($r('app.color.app_color_text_primary'))
.opacity(app_item['checked'] ? 0.5 : 1.0)
.decoration(app_item['checked'] ? TextDecorationType.LineThrough : TextDecorationType.None)
Blank()
Button('删除')
.fontSize(12)
.type(ButtonType.Normal)
.backgroundColor($r('app.color.app_color_danger'))
.onClick(() => {
this.app_items.splice(app_index, 1);
})
}
.width('100%')
.padding(12)
.backgroundColor($r('app.color.app_color_white'))
.borderRadius(8)
}
})
}
.width('100%')
.layoutWeight(1)
ForEach的关键参数:
| 参数 | 说明 |
|---|---|
| this.app_items | 要遍历的数组 |
| app_item | 当前遍历到的元素 |
| app_index | 当前元素的索引(可选) |
ForEach的渲染机制:
- 数组中每个元素渲染一个ListItem
- 使用索引追踪元素,便于删除操作
- 数组变化时自动重新渲染列表
3.4 切换完成状态
Checkbox组件用于切换物品的完成状态:
Checkbox()
.select(app_item['checked'])
.onChange((app_value: boolean) => {
this.app_items[app_index]['checked'] = app_value;
})
Checkbox的关键属性和方法:
| 属性/方法 | 说明 |
|---|---|
| select | 设置复选框的选中状态 |
| onChange | 选中状态变化时的回调 |
完成状态变化的视觉效果:
Text(app_item['name'])
.opacity(app_item['checked'] ? 0.5 : 1.0) // 半透明效果
.decoration(app_item['checked'] ? TextDecorationType.LineThrough : TextDecorationType.None) // 删除线效果
当物品被标记为完成时:
- 文字变为半透明(opacity: 0.5)
- 文字添加删除线(decoration: LineThrough)
3.5 删除物品功能
splice方法用于从数组中删除元素:
Button('删除')
.onClick(() => {
this.app_items.splice(app_index, 1);
})
splice方法的参数:
| 参数 | 值 | 说明 |
|---|---|---|
| app_index | 0 | 要删除元素的起始索引 |
| 1 | 1 | 要删除的元素数量 |
splice方法的特点:
- 直接修改原数组
- 自动触发状态更新
- 删除后后续元素自动重新索引
3.6 统计数据计算
统计区域显示待购买和已完成的数量:
Row({ space: 16 }) {
Text(`待购买: ${this.app_getUncheckedCount()} 项`)
.fontSize(14)
.fontColor($r('app.color.app_color_text_secondary'))
Text(`已完成: ${this.app_getCheckedCount()} 项`)
.fontSize(14)
.fontColor($r('app.color.app_color_success'))
}
统计方法的实现:
private app_getUncheckedCount(): number {
let app_count: number = 0;
for (let app_i: number = 0; app_i < this.app_items.length; app_i++) {
if (!this.app_items[app_i]['checked']) {
app_count++;
}
}
return app_count;
}
private app_getCheckedCount(): number {
let app_count: number = 0;
for (let app_i: number = 0; app_i < this.app_items.length; app_i++) {
if (this.app_items[app_i]['checked']) {
app_count++;
}
}
return app_count;
}
注意:由于ArkTS不支持解构赋值和部分数组方法,统计使用了传统的for循环实现。
4. UI布局设计
4.1 整体布局结构
购物清单应用的UI布局采用垂直堆叠的Column容器:
build() {
Column() {
CommonTitleBar({
app_title: '购物清单',
app_showBack: true
})
Column({ space: 16 }) {
// 输入区域
// 统计区域
// 列表区域
}
.width('100%')
.padding(16)
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.app_color_background'))
}
4.2 输入区域设计
输入区域包含文本输入框和添加按钮:
Row({ space: 12 }) {
TextInput({ placeholder: '添加新物品' })
.width('70%')
.onChange((app_value: string) => {
this.app_newItem = app_value;
})
Button('添加')
.width('30%')
.onClick(() => {
// 添加逻辑
})
}
设计要点解析:
输入框:占70%宽度,留出空间给按钮
按钮:占30%宽度,提供足够的点击区域
比例分配:70:30的比例在移动端设计中较为常见
4.3 统计区域设计
统计区域显示待购买和已完成物品的数量:
Row({ space: 16 }) {
Text(`待购买: ${this.app_getUncheckedCount()} 项`)
.fontSize(14)
.fontColor($r('app.color.app_color_text_secondary'))
Text(`已完成: ${this.app_getCheckedCount()} 项`)
.fontSize(14)
.fontColor($r('app.color.app_color_success'))
}
设计要点解析:
左右分布:两个统计项水平排列
颜色区分:待购买用普通灰色,已完成用成功绿色
动态数值:数值由方法计算得出,实时更新
4.4 列表区域设计
列表区域是购物清单应用的核心界面:
List() {
ForEach(this.app_items, (app_item: Record<string, boolean>, app_index: number) => {
ListItem() {
Row() {
Checkbox()
.select(app_item['checked'])
.onChange((app_value: boolean) => {
this.app_items[app_index]['checked'] = app_value;
})
Text(app_item['name'])
.fontSize(16)
.fontColor($r('app.color.app_color_text_primary'))
.opacity(app_item['checked'] ? 0.5 : 1.0)
.decoration(app_item['checked'] ? TextDecorationType.LineThrough : TextDecorationType.None)
Blank()
Button('删除')
.fontSize(12)
.type(ButtonType.Normal)
.backgroundColor($r('app.color.app_color_danger'))
.onClick(() => {
this.app_items.splice(app_index, 1);
})
}
.width('100%')
.padding(12)
.backgroundColor($r('app.color.app_color_white'))
.borderRadius(8)
}
})
}
.width('100%')
.layoutWeight(1)
设计要点解析:
List容器:提供可滚动列表的基础设施
layoutWeight(1):占据剩余的全部空间,实现自适应高度
Row布局:水平排列复选框、物品名称和删除按钮
Blank():自动填充中间空间,将删除按钮推到右侧
圆角卡片:每个列表项都是带圆角的白色卡片
5. 列表类应用开发要点
5.1 List组件基础
List是ArkUI中用于展示长列表的容器组件:
List() {
// ListItem子组件
}
.width('100%')
.height('100%')
List组件的特点:
- 支持大量数据的高效渲染
- 自动处理滚动和复用
- 与ForEach配合实现动态列表
5.2 ForEach循环渲染
ForEach是ArkUI中实现循环渲染的组件:
ForEach(arr, (item, index) => {
// 渲染逻辑
})
ForEach的渲染流程:
- 接收数组作为数据源
- 遍历数组每个元素
- 为每个元素执行渲染逻辑
- 返回对应的UI组件
5.3 数组状态管理
ArkTS中数组状态管理的注意事项:
正确做法:
// 使用push添加元素
this.app_items.push(newItem);
// 使用splice删除元素
this.app_items.splice(index, 1);
// 直接修改元素属性(需要确保触发更新)
this.app_items[index]['checked'] = true;
ArkTS限制:
- 不支持解构赋值
- 不支持filter、map等高阶数组方法
- 不支持通过索引直接赋值新对象
5.4 列表性能优化
列表性能优化的常用方法:
保持Item简单:避免在Item中执行复杂计算
使用layoutWeight:正确设置列表项的权重
懒加载:对于超长列表,考虑使用懒加载
List() {
ForEach(this.app_items, (app_item, index) => {
ListItem() {
// 简单的Item内容
}
})
}
6. ArkTS核心特性应用
6.1 Record类型使用
购物清单应用使用Record类型定义物品结构:
@State app_items: Record<string, boolean>[] = [];
Record类型的特点:
- 键的类型固定为string
- 值的类型固定为boolean
- 适合简单的键值对数据结构
- 不需要预先定义接口
6.2 ForEach组件详解
ForEach是ArkUI中实现列表渲染的核心组件:
ForEach(
this.app_items, // 数据源
(app_item: Record<string, boolean>, app_index: number) => { // 回调
ListItem() { ... } // 渲染内容
}
)
ForEach的关键点:
- 第一个参数是数组
- 第二个参数是生成器函数
- 生成器返回要渲染的UI组件
- 支持可选的索引参数
6.3 Checkbox组件使用
Checkbox是ArkUI中的复选框组件:
Checkbox()
.select(app_item['checked'])
.onChange((app_value: boolean) => {
// 处理选中状态变化
})
Checkbox的属性:
| 属性 | 类型 | 说明 |
|---|---|---|
| select | boolean | 当前选中状态 |
Checkbox的事件:
| 事件 | 回调参数 | 说明 |
|---|---|---|
| onChange | boolean | 选中状态变化时触发 |
6.4 TextInput组件使用
TextInput是ArkUI中的文本输入组件:
TextInput({ placeholder: '添加新物品' })
.width('70%')
.onChange((app_value: string) => {
this.app_newItem = app_value;
})
TextInput的关键属性:
| 属性 | 说明 |
|---|---|
| placeholder | 占位提示文字 |
| text | 输入框的文本值 |
TextInput的事件:
| 事件 | 回调参数 | 说明 |
|---|---|---|
| onChange | string | 输入内容变化时触发 |
7. 扩展与展望
7.1 当前功能总结
购物清单应用实现了以下核心功能:
| 功能模块 | 实现描述 |
|---|---|
| 添加物品 | 通过输入框和按钮添加新物品 |
| 列表展示 | 使用List和ForEach渲染物品列表 |
| 切换完成 | 使用Checkbox切换物品完成状态 |
| 删除物品 | 使用splice方法删除物品 |
| 统计显示 | 实时计算待购买/已完成数量 |
| 视觉效果 | 完成项半透明+删除线效果 |
7.2 功能扩展方向
基于当前的购物清单应用架构,可以进行以下功能扩展:
数据持久化:使用AppStorage保存购物清单:
aboutToDisappear(): void {
app_setString('shopping_items', JSON.stringify(this.app_items));
}
aboutToAppear(): void {
const app_stored: string = app_getString('shopping_items', '[]');
try {
this.app_items = JSON.parse(app_stored);
} catch (error) {
console.error('加载购物清单失败');
}
}
编辑物品:支持修改物品名称:
Button('编辑')
.onClick(() => {
// 显示编辑对话框
// 更新物品名称
})
分类管理:支持物品分类:
@State app_category: string = '全部';
interface ShoppingItem {
name: string;
checked: boolean;
category: string;
}
批量操作:支持全选、批量删除:
Button('全选')
.onClick(() => {
for (let app_i: number = 0; app_i < this.app_items.length; app_i++) {
this.app_items[app_i]['checked'] = true;
}
})
Button('清空已完成')
.onClick(() => {
// 过滤掉已完成的项
let app_unchecked: Record<string, boolean>[] = [];
for (let app_i: number = 0; app_i < this.app_items.length; app_i++) {
if (!this.app_items[app_i]['checked']) {
app_unchecked.push(this.app_items[app_i]);
}
}
this.app_items = app_unchecked;
})
拖拽排序:支持调整物品顺序:
List() {
ForEach(this.app_items, (app_item, index) => {
ListItem() {
Row() {
// 物品内容
}
.draggable(true) // 启用拖拽
}
})
}
搜索功能:支持搜索和过滤:
@State app_searchText: string = '';
TextInput({ placeholder: '搜索物品' })
.onChange((app_value: string) => {
this.app_searchText = app_value;
})
// 在ForEach中过滤
ForEach(this.app_items.filter(item => item['name'].includes(this.app_searchText)), ...)
8. 技术要点总结
8.1 核心代码模块
购物清单应用的代码结构:
@Entry
@Component
struct ShoppingList {
@State app_items: Record<string, boolean>[] = [];
@State app_newItem: string = '';
build() {
Column() {
CommonTitleBar({...})
Column({ space: 16 }) {
// 输入区域
// 统计区域
// 列表区域(List + ForEach)
}
}
}
private app_getUncheckedCount(): number {...}
private app_getCheckedCount(): number {...}
}
8.2 关键技术点
| 技术点 | 在本应用中的体现 |
|---|---|
| List组件 | 购物清单的容器 |
| ForEach组件 | 遍历渲染物品列表 |
| Checkbox组件 | 切换物品完成状态 |
| TextInput组件 | 输入新物品名称 |
| Record类型 | 物品数据结构 |
| splice方法 | 删除数组元素 |
| push方法 | 添加数组元素 |
| layoutWeight | 自适应列表高度 |
8.3 数组操作方法
| 方法 | 用途 | 示例 |
|---|---|---|
| push | 添加元素到末尾 | this.app_items.push(item) |
| splice | 删除指定位置元素 | this.app_items.splice(index, 1) |
9. 完整代码结构
import { CommonTitleBar } from '../../components/CommonTitleBar';
@Entry
@Component
struct ShoppingList {
@State app_items: Record<string, boolean>[] = [];
@State app_newItem: string = '';
build() {
Column() {
CommonTitleBar({
app_title: '购物清单',
app_showBack: true
})
Column({ space: 16 }) {
Row({ space: 12 }) {
TextInput({ placeholder: '添加新物品' })
.width('70%')
.onChange((app_value: string) => {
this.app_newItem = app_value;
})
Button('添加')
.width('30%')
.onClick(() => {
if (this.app_newItem !== '') {
let app_item: Record<string, boolean> = {
'name': this.app_newItem,
'checked': false
};
this.app_items.push(app_item);
this.app_newItem = '';
}
})
}
Row({ space: 16 }) {
Text(`待购买: ${this.app_getUncheckedCount()} 项`)
.fontSize(14)
.fontColor($r('app.color.app_color_text_secondary'))
Text(`已完成: ${this.app_getCheckedCount()} 项`)
.fontSize(14)
.fontColor($r('app.color.app_color_success'))
}
List() {
ForEach(this.app_items, (app_item: Record<string, boolean>, app_index: number) => {
ListItem() {
Row() {
Checkbox()
.select(app_item['checked'])
.onChange((app_value: boolean) => {
this.app_items[app_index]['checked'] = app_value;
})
Text(app_item['name'])
.fontSize(16)
.fontColor($r('app.color.app_color_text_primary'))
.opacity(app_item['checked'] ? 0.5 : 1.0)
.decoration(app_item['checked'] ? TextDecorationType.LineThrough : TextDecorationType.None)
Blank()
Button('删除')
.fontSize(12)
.type(ButtonType.Normal)
.backgroundColor($r('app.color.app_color_danger'))
.onClick(() => {
this.app_items.splice(app_index, 1);
})
}
.width('100%')
.padding(12)
.backgroundColor($r('app.color.app_color_white'))
.borderRadius(8)
}
})
}
.width('100%')
.layoutWeight(1)
}
.width('100%')
.padding(16)
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.app_color_background'))
}
private app_getUncheckedCount(): number {
let app_count: number = 0;
for (let app_i: number = 0; app_i < this.app_items.length; app_i++) {
if (!this.app_items[app_i]['checked']) {
app_count++;
}
}
return app_count;
}
private app_getCheckedCount(): number {
let app_count: number = 0;
for (let app_i: number = 0; app_i < this.app_items.length; app_i++) {
if (this.app_items[app_i]['checked']) {
app_count++;
}
}
return app_count;
}
}
10. 结语
购物清单应用作为一款待办事项类应用,展示了HarmonyOS ArkUI框架在列表类应用开发方面的核心能力。通过List、ForEach、Checkbox等组件的组合使用,实现了添加、完成标记、删除等完整的功能流程。
从技术角度来看,应用的核心亮点在于列表渲染和数组状态管理。ForEach组件配合List组件实现了高效列表渲染,push和splice方法实现了数组的增删操作,Checkbox组件实现了交互功能。
从应用设计的角度来看,购物清单应用遵循了"简洁直观、操作便捷"的设计原则。每个列表项都清晰地展示了物品名称、完成状态和删除按钮,用户可以快速完成各种操作。半透明和删除线效果让已完成项目一目了然。
更多推荐



所有评论(0)