项目已开源,开源地址: 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---标识这是一个自定义组件
@Proptaskstring-从父组件接收的任务文本,只读属性
@StateshowActionsbooleanfalse组件内部状态,控制操作按钮的显示与隐藏

2.2 装饰器的作用与区别

2.2.1 @Component装饰器

@Component装饰器用于定义自定义组件,它告诉框架这是一个可复用的UI组件,具有自己的生命周期和渲染逻辑。

2.2.2 @Prop装饰器

@Prop装饰器用于定义从父组件接收的属性,特点包括:

  1. 单向数据流:父组件可以修改属性值,子组件只能读取不能修改
  2. 响应式:当父组件中的值变化时,子组件会自动更新
  3. 简单传递:适用于传递简单数据类型或只读对象

2.2.3 @State装饰器

@State装饰器用于定义组件的内部状态,特点包括:

  1. 组件私有:状态只在组件内部可见和修改
  2. 响应式:状态变化会触发组件重新渲染
  3. 状态持久:在组件生命周期内保持状态

在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属性详解

属性/参数作用
space16设置子组件之间的水平间距为16vp
width100%设置Row宽度占父容器的100%
padding{ left: 12,right:12, top: 16, bottom: 16 }设置内边距,上下16vp,左右12vp
backgroundColor0xFFFFFF设置背景色为白色
borderRadius8设置边框圆角为8vp
shadow{ radius: 2, color: 0x05000000 }设置阴影效果,营造卡片视觉

3.3 卡片式设计的实现

.backgroundColor(0xFFFFFF)
.borderRadius(8)
.shadow({ radius: 2, color: 0x05000000 })

这三个属性的组合实现了卡片式设计:

  1. 白色背景提供了与页面背景的对比
  2. 圆角边框柔化了卡片的视觉边界
  3. 轻微的阴影效果增强了层次感,使卡片看起来略微悬浮

阴影参数解析:

参数说明
radius2阴影扩散半径,值越大阴影越模糊
color0x05000000阴影颜色,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属性详解

属性/参数作用
space4设置子组件之间的垂直间距为4vp

4.3 文本组件的实现

4.3.1 任务标题

Text(this.task)
    .fontSize(16)
    .fontWeight(500)
属性作用
构造参数this.task设置文本内容,来自@Prop装饰的task属性
fontSize16设置字体大小为16vp
fontWeight500设置字体粗细为中等偏粗

4.3.2 任务日期

Text('2025-05-30 14:00')
    .fontSize(12)
    .fontColor(0x666666)
属性作用
构造参数'2025-05-30 14:00'设置文本内容为固定的日期时间文本
fontSize12设置字体大小为12vp,小于标题字号
fontColor0x666666设置字体颜色为深灰色,弱化视觉重要性

4.4 文本层次设计

任务内容区域的文本设计遵循了明确的视觉层次:

  1. 主要信息(任务标题):较大字号(16vp)、较粗字重(500)、默认黑色
  2. 次要信息(任务日期):较小字号(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布局属性

属性/参数作用
space8设置按钮之间的水平间距为8vp
alignItemsVerticalAlign.Center设置子组件在垂直方向上居中对齐
justifyContentFlexAlign.Center设置子组件在水平方向上居中对齐

5.3 按钮样式设计

5.3.1 编辑按钮

Button('编辑')
    .width(48)
    .height(28)
    .fontSize(12)
    .backgroundColor(0xE0F5FF)
    .fontColor(0x007DFF)
属性作用
构造参数'编辑'设置按钮文本
width48设置按钮宽度为48vp
height28设置按钮高度为28vp
fontSize12设置字体大小为12vp
backgroundColor0xE0F5FF设置背景色为浅蓝色
fontColor0x007DFF设置文字颜色为蓝色

5.3.2 删除按钮

Button('删除')
    .width(48)
    .height(28)
    .fontSize(12)
    .backgroundColor(0xFFF0F0)
    .fontColor(0xFF4D4F53)
属性作用
构造参数'删除'设置按钮文本
width48设置按钮宽度为48vp
height28设置按钮高度为28vp
fontSize12设置字体大小为12vp
backgroundColor0xFFF0F0设置背景色为浅红色
fontColor0xFF4D4F53设置文字颜色为红色

5.4 按钮的视觉差异化

两个按钮使用了不同的颜色方案来区分不同的操作类型:

  1. 编辑按钮:蓝色系(浅蓝背景 + 蓝色文字),表示中性操作
  2. 删除按钮:红色系(浅红背景 + 红色文字),表示危险操作

这种颜色编码符合用户的心理预期,使界面更加直观易用。

6. 交互事件处理

6.1 悬停事件的实现

.onHover((isHover: boolean, event: HoverEvent)=>{
    if (isHover) {this.showActions = true}else{
        this.showActions = false
    }
})

onHover事件用于检测鼠标是否悬停在组件上,它接收一个回调函数,该函数有两个参数:

参数类型说明
isHoverboolean表示鼠标是否悬停在组件上
eventHoverEvent包含事件详细信息的对象

6.2 状态管理与UI更新

if (isHover) {this.showActions = true}else{
    this.showActions = false
}

这段代码根据悬停状态更新showActions状态变量:

  1. 当鼠标悬停在任务项上时(isHover为true),将showActions设为true,显示操作按钮
  2. 当鼠标离开任务项时(isHover为false),将showActions设为false,隐藏操作按钮

由于showActions是使用@State装饰器定义的响应式状态变量,当其值变化时,框架会自动重新渲染组件,实现操作按钮的动态显示与隐藏。

6.3 交互设计的优势

这种基于悬停的交互设计有以下优势:

  1. 界面简洁:默认情况下不显示操作按钮,减少视觉干扰
  2. 按需显示:只有当用户需要操作时(鼠标悬停),才显示相关按钮
  3. 直观反馈:提供即时的视觉反馈,增强用户体验
  4. 空间节省:在不牺牲功能的情况下,节省界面空间

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 代码结构分析

  1. 组件定义:使用@Component装饰器定义TaskItem自定义组件
  2. 属性与状态:定义@Prop属性接收任务文本,定义@State状态控制操作按钮显示
  3. 布局结构

    • 外层Row:水平排列任务内容和操作按钮
    • 内层Column:垂直排列任务标题和日期
    • 条件渲染Row:根据状态显示或隐藏操作按钮
  4. 样式设置:设置卡片式样式,包括背景色、圆角和阴影
  5. 交互处理:通过onHover事件实现鼠标悬停交互

7.2 布局嵌套层次

本案例展示了多层嵌套布局的实现方式:

  1. 第一层:TaskItem组件的Row(水平排列)
  2. 第二层:左侧Column(垂直排列)和右侧条件渲染Row(水平排列)
  3. 第三层:文本组件和按钮组件

这种多层嵌套的布局结构能够实现复杂的界面设计,同时保持代码的清晰和可维护性。

8. 总结

通过本教程的两个部分,我们详细讲解了如何使用Column和Row组件的嵌套组合,结合自定义组件和条件渲染,创建一个交互式任务列表


全栈若城
1 声望2 粉丝