项目已开源,开源地址: https://gitcode.com/nutpi/HarmonyosNextCaseStudyTutorial , 欢迎fork & star
效果演示
1. 引言
在上一部分中,我们介绍了任务列表的基础结构、数据模型设计以及外层Column的实现。本教程将继续深入探讨TaskItem组件的内部结构,包括Row布局的实现、条件渲染的使用以及交互事件的处理,帮助开发者掌握更复杂的布局和交互技巧,创建功能丰富、用户体验良好的任务列表界面。
2. TaskItem组件设计
2.1 组件定义与状态管理
@Component struct TaskItem { @Prop task: string @State showActions: boolean = false build() { // 组件内容 } }
装饰器 |
属性 |
类型 |
初始值 |
说明 |
@Component |
- |
- |
- |
标识这是一个自定义组件 |
@Prop |
task |
string |
- |
从父组件接收的任务文本,只读属性 |
@State |
showActions |
boolean |
false |
组件内部状态,控制操作按钮的显示与隐藏 |
2.2 装饰器的作用与区别
2.2.1 @Component装饰器
@Component装饰器用于定义自定义组件,它告诉框架这是一个可复用的UI组件,具有自己的生命周期和渲染逻辑。
2.2.2 @Prop装饰器
@Prop装饰器用于定义从父组件接收的属性,特点包括:
- 单向数据流:父组件可以修改属性值,子组件只能读取不能修改
- 响应式:当父组件中的值变化时,子组件会自动更新
- 简单传递:适用于传递简单数据类型或只读对象
2.2.3 @State装饰器
@State装饰器用于定义组件的内部状态,特点包括:
- 组件私有:状态只在组件内部可见和修改
- 响应式:状态变化会触发组件重新渲染
- 状态持久:在组件生命周期内保持状态
在TaskItem组件中,我们使用@State装饰器定义了showActions状态,用于控制操作按钮的显示与隐藏,初始值为false(隐藏状态)。
3. Row布局实现
3.1 基本结构
Row({ space: 16 }) { // 任务内容(垂直排列) Column({ space: 4 }) { // 文本组件 } // 操作按钮(水平排列,悬停显示) if (this.showActions) { Row({ space: 8 }) { // 按钮组件 } .alignItems(VerticalAlign.Center) .justifyContent(FlexAlign.Center) } } .width('100%') .padding({ left: 12,right:12, top: 16, bottom: 16 }) .backgroundColor(0xFFFFFF) .borderRadius(8) .shadow({ radius: 2, color: 0x05000000 }) .onHover((isHover: boolean, event: HoverEvent)=>{ // 悬停事件处理 })
每个任务项使用Row组件实现水平布局,将任务内容和操作按钮分别放置在左右两侧。
3.2 Row属性详解
属性/参数 |
值 |
作用 |
space |
16 |
设置子组件之间的水平间距为16vp |
width |
100% |
设置Row宽度占父容器的100% |
padding |
{ left: 12,right:12, top: 16, bottom: 16 } |
设置内边距,上下16vp,左右12vp |
backgroundColor |
0xFFFFFF |
设置背景色为白色 |
borderRadius |
8 |
设置边框圆角为8vp |
shadow |
{ radius: 2, color: 0x05000000 } |
设置阴影效果,营造卡片视觉 |
3.3 卡片式设计的实现
.backgroundColor(0xFFFFFF) .borderRadius(8) .shadow({ radius: 2, color: 0x05000000 })
这三个属性的组合实现了卡片式设计:
- 白色背景提供了与页面背景的对比
- 圆角边框柔化了卡片的视觉边界
- 轻微的阴影效果增强了层次感,使卡片看起来略微悬浮
阴影参数解析:
参数 |
值 |
说明 |
radius |
2 |
阴影扩散半径,值越大阴影越模糊 |
color |
0x05000000 |
阴影颜色,0x05表示透明度为5%的黑色阴影 |
4. 任务内容区域的Column布局
4.1 基本结构
Column({ space: 4 }) { Text(this.task) .fontSize(16) .fontWeight(500) Text('2025-05-30 14:00') .fontSize(12) .fontColor(0x666666) }
任务内容区域使用Column组件垂直排列任务标题和日期信息。
4.2 Column属性详解
属性/参数 |
值 |
作用 |
space |
4 |
设置子组件之间的垂直间距为4vp |
4.3 文本组件的实现
4.3.1 任务标题
Text(this.task) .fontSize(16) .fontWeight(500)
属性 |
值 |
作用 |
构造参数 |
this.task |
设置文本内容,来自@Prop装饰的task属性 |
fontSize |
16 |
设置字体大小为16vp |
fontWeight |
500 |
设置字体粗细为中等偏粗 |
4.3.2 任务日期
Text('2025-05-30 14:00') .fontSize(12) .fontColor(0x666666)
属性 |
值 |
作用 |
构造参数 |
'2025-05-30 14:00' |
设置文本内容为固定的日期时间文本 |
fontSize |
12 |
设置字体大小为12vp,小于标题字号 |
fontColor |
0x666666 |
设置字体颜色为深灰色,弱化视觉重要性 |
4.4 文本层次设计
任务内容区域的文本设计遵循了明确的视觉层次:
- 主要信息(任务标题):较大字号(16vp)、较粗字重(500)、默认黑色
- 次要信息(任务日期):较小字号(12vp)、默认字重、灰色(0x666666)
这种设计使用户能够快速识别重要信息,同时在需要时也能获取次要信息,提高了界面的可读性和信息层次感。
5. 操作按钮区域的条件渲染
5.1 条件渲染的实现
if (this.showActions) { Row({ space: 8 }) { Button('编辑') .width(48) .height(28) .fontSize(12) .backgroundColor(0xE0F5FF) .fontColor(0x007DFF) Button('删除') .width(48) .height(28) .fontSize(12) .backgroundColor(0xFFF0F0) .fontColor(0xFF4D4F53) } .alignItems(VerticalAlign.Center) .justifyContent(FlexAlign.Center) }
条件渲染使用if语句实现,只有当showActions为true时,才会渲染操作按钮区域。
5.2 Row布局属性
属性/参数 |
值 |
作用 |
space |
8 |
设置按钮之间的水平间距为8vp |
alignItems |
VerticalAlign.Center |
设置子组件在垂直方向上居中对齐 |
justifyContent |
FlexAlign.Center |
设置子组件在水平方向上居中对齐 |
5.3 按钮样式设计
5.3.1 编辑按钮
Button('编辑') .width(48) .height(28) .fontSize(12) .backgroundColor(0xE0F5FF) .fontColor(0x007DFF)
属性 |
值 |
作用 |
构造参数 |
'编辑' |
设置按钮文本 |
width |
48 |
设置按钮宽度为48vp |
height |
28 |
设置按钮高度为28vp |
fontSize |
12 |
设置字体大小为12vp |
backgroundColor |
0xE0F5FF |
设置背景色为浅蓝色 |
fontColor |
0x007DFF |
设置文字颜色为蓝色 |
5.3.2 删除按钮
Button('删除') .width(48) .height(28) .fontSize(12) .backgroundColor(0xFFF0F0) .fontColor(0xFF4D4F53)
属性 |
值 |
作用 |
构造参数 |
'删除' |
设置按钮文本 |
width |
48 |
设置按钮宽度为48vp |
height |
28 |
设置按钮高度为28vp |
fontSize |
12 |
设置字体大小为12vp |
backgroundColor |
0xFFF0F0 |
设置背景色为浅红色 |
fontColor |
0xFF4D4F53 |
设置文字颜色为红色 |
5.4 按钮的视觉差异化
两个按钮使用了不同的颜色方案来区分不同的操作类型:
- 编辑按钮:蓝色系(浅蓝背景 + 蓝色文字),表示中性操作
- 删除按钮:红色系(浅红背景 + 红色文字),表示危险操作
这种颜色编码符合用户的心理预期,使界面更加直观易用。
6. 交互事件处理
6.1 悬停事件的实现
.onHover((isHover: boolean, event: HoverEvent)=>{ if (isHover) {this.showActions = true}else{ this.showActions = false } })
onHover事件用于检测鼠标是否悬停在组件上,它接收一个回调函数,该函数有两个参数:
参数 |
类型 |
说明 |
isHover |
boolean |
表示鼠标是否悬停在组件上 |
event |
HoverEvent |
包含事件详细信息的对象 |
6.2 状态管理与UI更新
if (isHover) {this.showActions = true}else{ this.showActions = false }
这段代码根据悬停状态更新showActions状态变量:
- 当鼠标悬停在任务项上时(isHover为true),将showActions设为true,显示操作按钮
- 当鼠标离开任务项时(isHover为false),将showActions设为false,隐藏操作按钮
由于showActions是使用@State装饰器定义的响应式状态变量,当其值变化时,框架会自动重新渲染组件,实现操作按钮的动态显示与隐藏。
6.3 交互设计的优势
这种基于悬停的交互设计有以下优势:
- 界面简洁:默认情况下不显示操作按钮,减少视觉干扰
- 按需显示:只有当用户需要操作时(鼠标悬停),才显示相关按钮
- 直观反馈:提供即时的视觉反馈,增强用户体验
- 空间节省:在不牺牲功能的情况下,节省界面空间
7. 完整代码分析
让我们回顾完整的TaskItem组件代码:
@Component struct TaskItem { @Prop task: string @State showActions: boolean = false build() { Row({ space: 16 }) { // 任务内容(垂直排列) Column({ space: 4 }) { Text(this.task) .fontSize(16) .fontWeight(500) Text('2025-05-30 14:00') .fontSize(12) .fontColor(0x666666) } // 操作按钮(水平排列,悬停显示) if (this.showActions) { Row({ space: 8 }) { Button('编辑') .width(48) .height(28) .fontSize(12) .backgroundColor(0xE0F5FF) .fontColor(0x007DFF) Button('删除') .width(48) .height(28) .fontSize(12) .backgroundColor(0xFFF0F0) .fontColor(0xFF4D4F53) } .alignItems(VerticalAlign.Center) .justifyContent(FlexAlign.Center) } } .width('100%') .padding({ left: 12,right:12, top: 16, bottom: 16 }) .backgroundColor(0xFFFFFF) .borderRadius(8) .shadow({ radius: 2, color: 0x05000000 }) .onHover((isHover: boolean, event: HoverEvent)=>{ if (isHover) {this.showActions = true}else{ this.showActions = false } }) // 鼠标悬停显示操作按钮 } }
7.1 代码结构分析
- 组件定义:使用@Component装饰器定义TaskItem自定义组件
- 属性与状态:定义@Prop属性接收任务文本,定义@State状态控制操作按钮显示
- 布局结构:
- 外层Row:水平排列任务内容和操作按钮
- 内层Column:垂直排列任务标题和日期
- 条件渲染Row:根据状态显示或隐藏操作按钮
- 样式设置:设置卡片式样式,包括背景色、圆角和阴影
- 交互处理:通过onHover事件实现鼠标悬停交互
7.2 布局嵌套层次
本案例展示了多层嵌套布局的实现方式:
- 第一层:TaskItem组件的Row(水平排列)
- 第二层:左侧Column(垂直排列)和右侧条件渲染Row(水平排列)
- 第三层:文本组件和按钮组件
这种多层嵌套的布局结构能够实现复杂的界面设计,同时保持代码的清晰和可维护性。
8. 总结
通过本教程的两个部分,我们详细讲解了如何使用Column和Row组件的嵌套组合,结合自定义组件和条件渲染,创建一个交互式任务列表