
前言
健康提醒列表 是 萌宠日记 首页底部的重要功能模块,它展示宠物即将到来的 驱虫、疫苗、体检 等健康事项。通过 ForEach 动态渲染 数据列表,每个提醒项包含 图标、标题、日期、倒计时 等要素,用户可以一目了然地掌握宠物的健康管理状态。
本文将从 萌宠日记 的健康提醒列表实现出发,深入解析 ForEach 动态渲染、列表项布局、数据绑定、以及交互反馈的设计。
一、健康提醒列表整体设计
1.1 数据模型
typescript
// HomePage.ets --- 健康提醒数据结构
interface HealthReminder {
icon: string // 图标(Emoji)
title: string // 提醒标题
date: string // 提醒日期
daysLeft: string // 倒计时文字
color: string // 图标背景色
}
private healthReminders: HealthReminder[] = [
{
icon: '🛡️',
title: '驱虫',
date: '2024.05.20',
daysLeft: '还有15天',
color: '#FFF3E0'
}
]
1.2 列表渲染
typescript
// 健康提醒区域
Column({ space: 12 }) {
// 标题行
Row() {
Text('健康提醒')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.fontColor('#333333')
Blank()
Text('+')
.fontSize(24)
.fontColor('#F5A623')
}
.width('100%')
// 列表项
ForEach(this.healthReminders, (reminder: HealthReminder) => {
Row({ space: 12 }) {
// 图标
Column() {
Text(reminder.icon).fontSize(24)
}
.width(44).height(44)
.backgroundColor(reminder.color)
.borderRadius(12)
.justifyContent(FlexAlign.Center)
// 标题和日期
Column({ space: 4 }) {
Text(reminder.title)
.fontSize(14)
.fontWeight(FontWeight.Medium)
.fontColor('#333333')
Text(reminder.date)
.fontSize(12)
.fontColor('#999999')
}
.alignItems(HorizontalAlign.Start)
Blank()
// 倒计时
Text(reminder.daysLeft)
.fontSize(12)
.fontColor('#F5A623')
// 右箭头
Text('›')
.fontSize(18)
.fontColor('#CCCCCC')
}
.width('100%')
.padding(12)
.backgroundColor('#FFFFFF')
.borderRadius(12)
})
}
.width('100%')
.padding({ left: 16, right: 16, bottom: 16 })
提示 :健康提醒列表使用 ForEach 动态渲染,数据驱动 UI。当提醒数据发生变化时(如新增、删除、更新倒计时),UI 会自动同步更新,这是 ArkTS 声明式编程的核心优势。
二、列表项布局详解
2.1 每行布局结构
┌─────────────────────────────────────────┐
│ ┌────┐ ┌──────────────┐ 还有15天 › │
│ │🛡️ │ │ 驱虫 │ │
│ │ │ │ 2024.05.20 │ │
│ └────┘ └──────────────┘ │
└─────────────────────────────────────────┘
2.2 布局分解
| 位置 | 组件 | 内容 | 说明 |
|---|---|---|---|
| 左侧 | Column | 图标 Emoji | 44×44vp 圆角容器 |
| 左中 | Column | 标题 + 日期 | 垂直排列,间距 4vp |
| 右中 | Blank | 弹性占位 | 将内容推到两端 |
| 右侧 | Text | 倒计时 | 橙色文字,引人注意 |
| 最右 | Text | › |
右箭头,暗示可点击 |
三、标题行设计
3.1 标题 + 添加按钮
typescript
Row() {
Text('健康提醒')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.fontColor('#333333')
Blank()
Text('+') // 添加按钮
.fontSize(24)
.fontColor('#F5A623')
}
3.2 添加按钮交互
typescript
Text('+')
.fontSize(24)
.fontColor('#F5A623')
.onClick(() => {
// 跳转到添加提醒页面
console.log('Add new reminder')
})
四、动态数据绑定
4.1 数据驱动 UI
typescript
// 数据变化时,UI 自动更新
@State healthReminders: HealthReminder[] = [
{ icon: '🛡️', title: '驱虫', date: '2024.05.20', daysLeft: '还有15天', color: '#FFF3E0' }
]
// 添加新提醒
addReminder(reminder: HealthReminder): void {
this.healthReminders.push(reminder)
// @State 装饰的数组变化后,UI 自动重新渲染
}
// 删除提醒
removeReminder(index: number): void {
this.healthReminders.splice(index, 1)
}
// 更新倒计时
updateDaysLeft(): void {
this.healthReminders = this.healthReminders.map(item => {
// 重新计算倒计时
return { ...item, daysLeft: this.calculateDaysLeft(item.date) }
})
}
4.2 @State 与数组变化
| 数组操作 | UI 是否更新 | 说明 |
|---|---|---|
push() |
✅ 更新 | 新增元素 |
splice() |
✅ 更新 | 删除/替换元素 |
pop() |
✅ 更新 | 移除末尾元素 |
直接赋值 |
✅ 更新 | this.arr = newArr |
修改元素属性 |
⚠️ 需解构 | 使用 ... 展开运算符创建新对象 |
五、倒计时计算
5.1 倒计时逻辑
typescript
// 计算倒计时
calculateDaysLeft(targetDate: string): string {
const today = new Date()
const target = new Date(targetDate)
const diffTime = target.getTime() - today.getTime()
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24))
if (diffDays > 0) {
return `还有${diffDays}天`
} else if (diffDays === 0) {
return '今天'
} else {
return `已过期${Math.abs(diffDays)}天`
}
}
5.2 倒计时样式
typescript
// 根据剩余天数显示不同颜色
getDaysLeftColor(daysLeft: string): string {
if (daysLeft.includes('今天')) {
return '#F44336' // 红色 --- 紧急
} else if (daysLeft.includes('已过期')) {
return '#F44336' // 红色 --- 已过期
} else {
return '#F5A623' // 橙色 --- 正常
}
}
六、列表项交互
6.1 点击事件
typescript
Row({ space: 12 }) {
// 列表项内容...
}
.width('100%')
.padding(12)
.backgroundColor('#FFFFFF')
.borderRadius(12)
.onClick(() => {
// 跳转到提醒详情/编辑页
console.log('Reminder clicked:', reminder.title)
})
6.2 完整交互设计
| 交互元素 | 行为 | 实现 |
|---|---|---|
| 列表项 | 点击跳转详情 | onClick |
| 添加按钮 | 跳转添加页 | onClick |
| 右箭头 | 视觉提示可点击 | Text('›') |
| 倒计时 | 状态指示 | 颜色变化 |
七、ForEach 渲染优化
7.1 key 生成器
typescript
// 为 ForEach 提供 key 生成器,提高渲染效率
ForEach(
this.healthReminders,
(item: HealthReminder) => {
ListItem() {
// 列表项内容
}
},
(item: HealthReminder) => item.title // key 生成器
)
7.2 带 key 与不带 key 的对比
| 对比维度 | 不带 key | 带 key |
|---|---|---|
| 渲染效率 | 重新渲染所有项 | 只更新变化的项 |
| 动画过渡 | 不支持 | 支持 item 动画 |
| 数据变化 | 全部重建 | 精准更新 |
| 推荐度 | 小列表可用 | 推荐使用 |
八、列表项样式统一
8.1 列表项容器
typescript
// 列表项的统一样式
Row({ space: 12 }) {
// 内容...
}
.width('100%')
.padding(12) // 内边距 12vp
.backgroundColor('#FFFFFF') // 白色背景
.borderRadius(12) // 12vp 圆角
8.2 列表项间距
typescript
// 列表项之间的间距由外层 Column 的 space 控制
Column({ space: 12 }) {
// 标题行
// 列表项 1
// 列表项 2(如果有)
}
九、空状态与加载状态
9.1 空状态
typescript
// 当没有提醒时显示空状态
if (this.healthReminders.length === 0) {
Column() {
Text('🎉')
.fontSize(48)
Text('暂无健康提醒')
.fontSize(14)
.fontColor('#999999')
.margin({ top: 8 })
Text('点击 + 添加提醒')
.fontSize(12)
.fontColor('#F5A623')
.margin({ top: 4 })
}
.width('100%')
.padding(24)
.alignItems(HorizontalAlign.Center)
}
9.2 加载状态
typescript
@State isLoading: boolean = true
aboutToAppear(): void {
// 模拟加载数据
setTimeout(() => {
this.isLoading = false
}, 1000)
}
// 加载中显示 Loading
if (this.isLoading) {
LoadingProgress()
.width(32).height(32)
.color('#F5A623')
}
十、最佳实践
10.1 列表设计原则
有序列表 --- 列表设计的 5 个原则:
- 数据驱动:使用 ForEach 动态渲染,数据变化 UI 自动更新
- 信息层级:图标 > 标题 > 日期 > 辅助信息,从左到右重要性递减
- 交互反馈:可点击的列表项提供点击反馈
- 状态指示:倒计时使用颜色区分紧急程度
- 空状态友好:列表为空时展示引导文案
10.2 萌宠日记健康提醒列表总结
| 设计要素 | 值 | 说明 |
|---|---|---|
| 布局 | Row + Column 嵌套 | 水平布局 + 垂直布局 |
| 图标容器 | 44×44vp | 圆角 12vp |
| 标题字号 | 14fp | 中等强调 |
| 日期字号 | 12fp | 辅助信息 |
| 倒计时色 | #F5A623 |
橙色引人注意 |
| 背景色 | #FFFFFF |
白色 |
| 圆角 | 12vp | 柔和 |
总结
本文从 萌宠日记 的 健康提醒列表 实现出发,深入解析了列表动态渲染和数据绑定的完整方法:
- 数据模型:HealthReminder 接口定义提醒数据结构
- 列表渲染:ForEach 动态渲染提醒列表
- 列表项布局:图标 + 标题 + 日期 + 倒计时 + 右箭头
- 标题行设计:标题 + 添加按钮
- 动态数据绑定:@State 驱动 UI 自动更新
- 倒计时计算:日期计算与颜色状态指示
- 交互反馈:点击跳转、添加按钮
- 空状态处理:无提醒时的引导展示
健康提醒列表展示了 ArkTS 中数据驱动 UI 的典型模式,理解这一模式能为构建更复杂的列表页面打下基础。
下一篇我们将深入 图标与 Emoji 在 UI 中的应用,解析 Emoji 作为 UI 图标的优势和选择策略。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源:
- ForEach 使用:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-foreach
- @State 装饰器:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-state
- Row 组件参考:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-row
- Column 组件参考:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-column
- Blank 组件:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-blank
- 文本溢出处理:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-text
- 列表性能优化:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/list-optimization
- 点击效果:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-universal-attributes-click-effect