HarmonyOS ArkTS 实战:用 @State 状态管理做一个待办清单页面
对刚接触 HarmonyOS 的开发者来说,最快理解 ArkUI 声明式开发的方式,不是先啃完所有概念,而是亲手做一个能跑起来的小页面。待办清单正好合适:它包含输入、列表渲染、状态变更和删除操作,麻雀虽小,五脏俱全。本文用 ArkTS 实现一个待办清单页面,并借此讲清 @State 的工作方式和几个新手最容易踩的坑。
一、准备工作
- 开发工具:DevEco Studio(建议使用与目标 SDK 匹配的版本)
- 新建项目时选择 Empty Ability 模板,语言选 ArkTS
- 页面文件位于
entry/src/main/ets/pages/Index.ets
二、先定义数据结构
待办事项有三个属性:唯一 id、标题和是否完成。用 interface 把结构先定下来,后面的状态操作会清晰很多:
interface TodoItem {
id: number
title: string
done: boolean
}
三、编写页面组件
ArkUI 是声明式 UI:你描述“界面应该长什么样”,框架负责在数据变化时刷新界面。驱动刷新的关键就是状态变量——用 @State 装饰的变量发生变化时,使用它的 UI 会自动重新渲染。
@Entry
@Component
struct TodoPage {
@State private todos: TodoItem[] = [
{ id: 1, title: '熟悉 ArkTS 基本语法', done: true },
{ id: 2, title: '完成待办清单页面', done: false }
]
@State private draft: string = ''
private nextId: number = 3
private addTodo(): void {
const title = this.draft.trim()
if (title.length === 0) {
return
}
this.todos = [...this.todos, { id: this.nextId, title: title, done: false }]
this.nextId += 1
this.draft = ''
}
private toggleTodo(id: number): void {
this.todos = this.todos.map((item: TodoItem): TodoItem => {
if (item.id === id) {
return { id: item.id, title: item.title, done: !item.done }
}
return item
})
}
private removeTodo(id: number): void {
this.todos = this.todos.filter((item: TodoItem): boolean => item.id !== id)
}
build() {
Column({ space: 12 }) {
Text('我的待办')
.fontSize(24)
.fontWeight(FontWeight.Bold)
Row({ space: 8 }) {
TextInput({ placeholder: '输入待办事项', text: this.draft })
.layoutWeight(1)
.onChange((value: string) => {
this.draft = value
})
Button('添加')
.onClick(() => {
this.addTodo()
})
}
.width('100%')
List({ space: 6 }) {
ForEach(this.todos, (item: TodoItem) => {
ListItem() {
Row({ space: 8 }) {
Checkbox()
.select(item.done)
.onChange(() => {
this.toggleTodo(item.id)
})
Text(item.title)
.layoutWeight(1)
.decoration({ type: item.done ? TextDecorationType.LineThrough : TextDecorationType.None })
.fontColor(item.done ? '#999999' : '#222222')
Button('删除')
.type(ButtonType.Normal)
.onClick(() => {
this.removeTodo(item.id)
})
}
.width('100%')
}
}, (item: TodoItem): string => item.id.toString())
}
.layoutWeight(1)
.width('100%')
}
.padding(16)
.width('100%')
.height('100%')
}
}
四、三个关键点
1. @State 只追踪“赋值”,不追踪“原地修改”
这是新手最常见的问题:直接写 this.todos.push(newItem) 或 item.done = true,界面有时不会刷新。原因是框架对状态的观测以变量重新赋值最可靠。稳妥的写法是生成新数组再赋值,比如添加时用展开语法 [...this.todos, newItem],切换完成状态时用 map 返回新对象。养成“不可变更新”的习惯,后面学 @Prop、@Link 时也会受益。
2. ForEach 的第三个参数是键值生成器,别省略
ForEach 渲染列表时靠 key 判断哪些元素是新增、删除或复用。上面用待办的 id 作为 key,这样勾选、删除时框架能准确定位每一项,不会出现勾选状态串行的问题。用数组下标当 key 在增删场景下容易出错,尽量用数据的唯一标识。
3. 输入框要用状态变量双向承接
TextInput 的 text 参数绑定 draft,再在 onChange 里把最新输入写回 draft,这样点击“添加”时才能拿到用户真正输入的内容。添加完成后把 draft 清空,输入框也会随之刷新为空。
五、可以继续扩展的方向
这个页面跑通之后,可以顺着下面的方向练手,每一步都是一个真实的知识点:
- 数据持久化:用首选项(Preferences)或关系型数据库保存待办,重启应用不丢失
- 拆分组件:把单个待办行抽成
@Component子组件,用 @Prop 接收数据、回调通知父组件 - 多页面跳转:加一个详情页,用路由传参,练习页面间数据传递
总结
待办清单虽小,却完整走了一遍 ArkUI 的核心思路:用 @State 管理页面状态,用声明式语法描述界面,用不可变更新保证刷新可靠。把这一页写明白,再去看更复杂的状态装饰器和组件通信,就不会觉得抽象了。建议动手敲一遍,并故意把 toggleTodo 改成原地修改试试,直观感受一下状态观测的边界——这种“踩坑式学习”比只看文档记得牢得多。
- 点赞
- 收藏
- 关注作者
评论(0)