鸿蒙开发-水果排行榜案例

本文详细介绍了如何使用声明式语法和组件化知识在鸿蒙系统中创建一个可刷新的水果排行榜页面,涉及数据渲染、组件状态管理以及自定义组件生命周期函数的实践。
摘要由CSDN通过智能技术生成

水果排行榜案例

本案例使用声明式语法和组件化基础知识,搭建一个可刷新的排行榜页面。在排行榜页面中,使用循环渲染控制语法来实现列表数据渲染,使用@Builder创建排行列表布局内容,使用装饰器@State、@Prop、@Link来管理组件状态。最后我们点击系统返回按键,来学习自定义组件生命周期函数。完成效果如图所示:

在这里插入图片描述

准备图片

首先准备案例中所需要的图片。在项目ets目录中创建images目录,放入“back.svg”和“loading.png”两个图片。

在这里插入图片描述

RankData

创建水果排行的类。

//RankData类 - 水果对象
export class RankData {
  name: string;
  vote: string; // 投票数
  id: string;

  constructor(id: string, name: string, vote: string) {
    this.id = id;
    this.name = name;
    this.vote = vote;
  }
}

TitleComponent

创建“TitleComponent”文件,创建一个带有标题和两个交互元素(返回图标和加载图标)的用户界面。图示和代码如下:

在这里插入图片描述

import AppContext from '@ohos.app.ability.common';  // 从鸿蒙的应用能力通用库中导入AppContext。

@Component  // 使用@Component装饰器标记这是一个组件。
export struct TitleComponent {  // 定义一个名为TitleComponent的结构体,作为组件的主体。

  @Link isRefreshData: boolean; // 定义一个名为isRefreshData的变量,类型为boolean,用于控制数据是否刷新。
  @State title: string  = "";   // 定义一个名为title的状态变量,类型为string,默认为空字符串。

  build() {  // 定义组件的构建方法。
    Row() {  // 创建一个行布局。
      Row() {  // 在行布局中嵌套另一个行布局。
        Image('images/back.svg')  // 插入一个图片元素,用于显示返回图标。
          .height(21)  // 设置图片的高度为21。
          .width(21)   // 设置图片的宽度为21。
          .margin({ right: 18 })  // 设置图片右侧的外边距为18。
          .onClick(() => {  // 为图片添加点击事件。
            let handler = getContext(this) as AppContext.UIAbilityContext;  // 获取当前组件的上下文,并转换为UIAbilityContext类型。
            handler.terminateSelf();  // 调用terminateSelf方法结束当前界面。
          })
        Text(this.title)  // 插入一个文本元素,显示标题。
          .fontSize(20)  // 设置文本的字体大小为20。
      }
      .width('50%')  // 设置内层行布局的宽度为父容器宽度的50%。
      .height('100%')  // 设置内层行布局的高度为父容器高度的100%。
      .justifyContent(FlexAlign.Start)  // 设置内层行布局的内容靠左对齐。

      Row() {  // 再创建一个行布局。
        Image('images/loading.png')  // 插入一个图片元素,用于显示加载图标。
          .height(22)  // 设置图片的高度为22。
          .width(22)   // 设置图片的宽度为22。
          .onClick(() => {  // 为图片添加点击事件。
            this.isRefreshData = !this.isRefreshData;  // 切换isRefreshData的值。
          })
      }
      .width('50%')  // 设置此行布局的宽度为父容器宽度的50%。
      .height('100%')  // 设置此行布局的高度为父容器高度的100%。
      .justifyContent(FlexAlign.End)  // 设置此行布局的内容靠右对齐。
    }
    .width('100%')  // 设置最外层行布局的宽度为100%。
    .padding({ left: 26, right: 26 })  // 设置左右的内边距为26。
    .margin({ top: 10 })  // 设置顶部的外边距为10。
    .height(47)  // 设置最外层行布局的高度为47。
    .justifyContent(FlexAlign.SpaceAround)  // 设置内容分布方式为平均分布。
  }
}

ListHeaderComponent

创建“ListHeaderComponent”组件,用于创建一个列表头部,显示列标题。图示和代码如下:
在这里插入图片描述

@Component  // 使用@Component装饰器标记这是一个组件。
export struct ListHeaderComponent {  // 定义一个名为ListHeaderComponent的结构体,作为组件的主体。

  paddingValue: Padding | Length = 0;  // 定义一个名为paddingValue的变量,用于设置内边距,可以是Padding类型或Length类型,默认值为0。
  widthValue: Length = 0;  // 定义一个名为widthValue的变量,用于设置组件的宽度,类型为Length,默认值为0。

  build() {  // 定义组件的构建方法。
    Row() {  // 创建一个行布局。
      Text('排名')  // 插入一个文本元素,内容为“排名”。
        .fontSize(14)  // 设置字体大小为14。
        .width('30%')  // 设置此文本元素的宽度占父容器的30%。
        .fontWeight(400)  // 设置字体的粗细为400(正常粗细)。
        .fontColor('#989A9C')  // 设置字体颜色为灰色(#989A9C)。
      Text('种类')  // 插入另一个文本元素,内容为“种类”。
        .fontSize(14)  // 设置字体大小为14。
        .width('50%')  // 设置此文本元素的宽度占父容器的50%。
        .fontWeight(400)  // 设置字体的粗细为400。
        .fontColor('#989A9C')  // 设置字体颜色为灰色。
      Text('得票数')  // 插入第三个文本元素,内容为“得票数”。
        .fontSize(14)  // 设置字体大小为14。
        .width('20%')  // 设置此文本元素的宽度占父容器的20%。
        .fontWeight(400)  // 设置字体的粗细为400。
        .fontColor('#989A9C')  // 设置字体颜色为灰色。
    }
    .width(this.widthValue)  // 设置行布局的宽度,使用之前定义的widthValue变量。
    .padding(this.paddingValue)  // 设置行布局的内边距,使用之前定义的paddingValue变量。
  }
}

ListItemComponent

创建“ListItemComponent”用于在UI界面上显示一行水果名称和得票数,同时包含交互效果。图示和代码如下:
在这里插入图片描述

@Component  // 使用 @Component 装饰器定义一个组件。
export struct ListItemComponent {  // 定义一个名为 ListItemComponent 的结构体,用于表示列表项组件。
  index?: number;  // 可选属性:表示列表项的索引(位置)。
  private name?: string;  // 私有属性:存储列表项的名称。
  vote: string = '';  // 属性:存储列表项的得票数,默认为空字符串。
  isSwitchDataSource: boolean = false;  // 属性:标志是否切换数据源,默认为假(false)。

  @State isChange: boolean = false;  // 使用 @State 装饰器,当 isChange 的值改变时,会自动刷新UI。

  build() {  // 定义 build 方法,用于构建组件的UI界面。
    Row() {  // 使用 Row 组件创建水平布局。
      Column() {  // 使用 Column 组件创建垂直布局。
        if (this.isRenderCircleText()) {  // 判断是否渲染圆形文本。
          if (this.index !== undefined) {  // 如果索引不为空,则渲染圆形文本。
            this.CircleText(this.index);  // 调用 CircleText 方法来渲染圆形文本。
          }
        } else {
          Text(this.index?.toString())  // 否则,渲染普通文本。
            .lineHeight(24)  // 设置文本的行高为24。
            .textAlign(TextAlign.Center)  // 设置文本对齐方式为居中。
            .width(24)  // 设置文本宽度为24。
            .fontWeight('400')  // 设置文本的字体粗细为400。
            .fontSize(14)  // 设置文本字体大小为14。
        }
      }
      .width('30%')  // 设置列的宽度为容器宽度的30%。
      .alignItems(HorizontalAlign.Start)  // 设置水平对齐方式为开始。

      Text(this.name)  // 创建一个 Text 组件用于显示名称。
        .width('50%')  // 设置文本宽度为容器宽度的50%。
        .fontWeight('500')  // 设置字体粗细为500。
        .fontSize(16)  // 设置字体大小为16。
        .fontColor(this.isChange ? "#007DFF" : "#182431")  // 设置字体颜色,当 isChange 为真时为蓝色,否则为深灰色。
      Text(this.vote)  // 创建一个 Text 组件用于显示得票数。
        .width('20%')  // 设置文本宽度为容器宽度的20%。
        .fontWeight('400')  // 设置字体粗细为400。
        .fontSize(14)  // 设置字体大小为14。
        .fontColor(this.isChange ? "#007DFF" : "#182431")  // 设置字体颜色,同上。
    }
    .height(48)  // 设置行组件的高度为48。
    .width('100%')  // 设置行组件的宽度为100%。
    .onClick(() => {  // 设置点击事件处理器。
      this.isSwitchDataSource = !this.isSwitchDataSource;  // 切换数据源标志。
      this.isChange = !this.isChange;  // 切换改变状态标志。
    })
  }

  @Builder CircleText(index: number) {  // 定义一个名为 CircleText 的方法,用于创建圆形文本。
    Row() {  // 使用 Row 组件。
      Text(this.index?.toString())  // 创建 Text 组件显示索引。
        .fontWeight('400')  // 设置字体粗细为400。
        .fontSize(14)  // 设置字体大小为14。
        .fontColor(Color.White);  // 设置字体颜色为白色。
    }
    .justifyContent(FlexAlign.Center)  // 设置内容居中对齐。
    .borderRadius(24)  // 设置边框半径为24,形成圆形。
    .size({ width: 24, height: 24})  // 设置尺寸为24x24。
    .backgroundColor("#007dff")  // 设置背景颜色为蓝色。
  }

  isRenderCircleText(): boolean {  // 定义一个方法判断是否渲染圆形文本。
    return this.index === 1 || this.index === 2 || this.index === 3;  // 对于索引1、2、3的项返回真,其他返回假。
  }
}

RankPage

定义“rankPage”的组件,用于显示一个排行榜页面,包括标题、列表头部和列表项。将以上所有组件组合形成最终排行榜效果。

import { ListHeaderComponent } from './ListHeaderComponent';  // 导入 ListHeaderComponent 组件。
import { ListItemComponent } from './ListItemComponent';  // 导入 ListItemComponent 组件。
import { RankData } from './RankData';  // 导入 RankData 类。
import { TitleComponent } from './TitleComponent';  // 导入 TitleComponent 组件。

@Entry  // 使用 @Entry 装饰器标识入口组件。
@Component  // 使用 @Component 装饰器定义组件。
struct RankPage {  // 定义名为 RankPage 的结构体组件。

  // 使用 @State 装饰器定义状态,存储两个不同的排行数据源。
  // 初始化第一个数据源,包含苹果、葡萄等水果的排名和得票数。
  @State dataSource1: RankData[] = [
    new RankData('1', '苹果', '12080'),
    new RankData('2', '葡萄', '10320'),
    new RankData('3', '西瓜', '9801'),
    new RankData('4', '香蕉', '8431'),
    new RankData('5', '菠萝', '7546'),
    new RankData('6', '榴莲', '7431'),
    new RankData('7', '红葡萄', '7187'),
    new RankData('8', '梨子', '7003'),
    new RankData('9', '杨桃', '6794'),
    new RankData('10','番石榴', '6721')
  ];

  // 初始化第二个数据源,包含另一组水果的排名和得票数。
  @State dataSource2: RankData[] = [
    new RankData('11', '西瓜', '8836'),
    new RankData('12', '苹果', '8521'),
    new RankData('13', '香蕉', '8431'),
    new RankData('14', '葡萄', '7909'),
    new RankData('15', '红葡萄', '7547'),
    new RankData('16', '梨子', '7433'),
    new RankData('17', '菠萝', '7186'),
    new RankData('18', '榴莲', '7023'),
    new RankData('19', '番石榴', '6794'),
    new RankData('20', '杨桃', '6721')

  ];
  @State isSwitchDataSource: boolean = true;  // 定义一个状态,用于控制是否切换数据源。

  private clickBackTimeRecord: number = 0;  // 私有变量,记录点击系统导航返回按钮的时间。

  build() {  // 定义 build 方法来构建UI界面。
    Column() {  // 使用 Column 组件创建垂直布局。
      TitleComponent({ isRefreshData: $isSwitchDataSource, title: "排行榜" })  // 添加标题组件。

      ListHeaderComponent({  // 添加列表头部组件。
        paddingValue: {  // 设置内边距。
          left: 15,
          right: 15
        },
        widthValue: '90%'  // 设置宽度值。
      })
        .margin({  // 设置外边距。
          top: 20,
          bottom: 15
        })

      this.RankList('90%')  // 调用 RankList 方法创建列表。
    }
    .backgroundColor("#F1F3F5")  // 设置背景颜色。
    .height('100%')  // 设置高度为100%。
    .width('100%')  // 设置宽度为100%。
  }

  @Builder RankList(widthValue: Length) {  // 使用 @Builder 装饰器定义 RankList 方法。
    Column() {  // 使用 Column 组件。
      List() {  // 创建 List 组件。
        ForEach(this.isSwitchDataSource ? this.dataSource1 : this.dataSource2,  // 根据状态选择数据源。
          (item: RankData, index?: number) => {  // 遍历数据项。
            ListItem() {  // 创建列表项。
              ListItemComponent({  // 使用 ListItemComponent 组件。
                index: (Number(index) + 1),  // 设置索引。
                name: item.name,  // 设置名称。
                vote: item.vote,  // 设置得票数。
                isSwitchDataSource: this.isSwitchDataSource  // 传递数据源切换状态。
              })
            }
          }, (item: RankData) => JSON.stringify(item))  // 使用 JSON.stringify 作为键函数。
      }
      .width('100%')  // 设置列表宽度为100%。
      .height('65%')  // 设置列表高度为65%。
      .divider({ strokeWidth: 1 })  // 设置列表项之间的分割线。
    }
    .padding({  // 设置内边距。
      left: 15,
      right: 15
    })
    .borderRadius(20)  // 设置边框圆角。
    .width(widthValue)  // 设置组件宽度。
    .alignItems(HorizontalAlign.Center)  // 设置水平对齐方式为居中。
    .backgroundColor(Color.White)  // 设置背景颜色为白色。
  }
}

  • 17
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值