当前位置:   article > 正文

鸿蒙 + Python 全栈开发一个排行榜应用_python鸿蒙开发

python鸿蒙开发

背景

本项目是一个用于练习鸿蒙开发的实用小项目,前后端都覆盖到位,这有助于提升开发者的整体设计能力。

相关技能点

一、渲染控制语法

条件渲染:使用 if/else 进行条件渲染。

循环渲染:开发框架提供循环渲染(ForEach 组件)来迭代数组,并为每个数组项创建相应的组件。

二、 @State、@Prop、@Link 组件状态管理装饰器和@Builder 装饰器:

@State 装饰的变量是组件内部的状态数据,当这些状态数据被修改时,将会调用所在组件的 build 方法进行 UI 刷新。

@Prop 与@State 有相同的语义,但初始化方式不同。@Prop 装饰的变量必须使用其父组件提供的@State 变量进行初始化,允许组件内部修改@Prop 变量,但更改不会通知给父组件,即@Prop 属于单向数据绑定。

@Link 装饰的变量可以和父组件的@State 变量建立双向数据绑定,需要注意的是:@Link 变量不能在组件内部进行初始化。

@Builder 装饰的方法用于定义组件的声明式 UI 描述,在一个自定义组件内快速生成多个布局内容。

三、组件生命周期函数

自定义组件的生命周期函数用于通知用户该自定义组件的生命周期,这些回调函数是私有的,在运行时由开发框架在特定的时间进行调用,不能从应用程序中手动调用这些回调函数,如下图所示。
在这里插入图片描述

需要注意的是,部分生命周期回调函数仅对@Entry 修饰的自定义组件生效,它们分别是:onPageShow、onPageHide、onBackPress。

四、数据请求

通过 HTTP 应用发起一个数据请求,支持常见的 GET、POST、OPTIONS、HEAD、PUT、DELETE、TRACE、CONNECT 方法。

五、Python Rest API

其实开发后端 API 并不困难,本项目将借助 ChatGPT 光速完成 API 的开发,大家马上就能获得到前后端打通的成就感。

代码结构

ArkTS 项目

├──entry/src/main/ets               // 代码区
│  ├──common                        // 公共文件目录
│  │  ├──bean
│  │  │  └──RankData.ets            // 实体类
│  │  └──constants
│  │     └──Constants.ets           // 常量
│  ├──entryability
│  │  └──EntryAbility.ts            // 应用的入口
│  ├──model
│  │  └──DataModel.ets              // 模拟数据
│  ├──pages
│  │  └──RankPage.ets               // 入口页面
│  ├──view                          // 自定义组件目录
│  │  ├──ListHeaderComponent.ets
│  │  ├──ListItemComponent.ets
│  │  └──TitleComponent.ets
│  └──viewmodel
│     └──RankViewModel.ets          // 视图业务逻辑类
└──entry/src/main/resources	    // 资源文件目录
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

Python 后端项目

使用@Link 封装标题组件

在 TitleComponent 文件中,首先使用 struct 对象创建自定义组件,然后使用@Link 修饰器管理 TitleComponent 组件内的状态变量 isRefreshData,状态变量 isRefreshData 值发生改变后,通过@Link 装饰器通知页面刷新 List 中的数据。

...
@Component
export struct TitleComponent {
  @Link isRefreshData: boolean; // 判断是否刷新数据
  @State title: Resource = $r('app.string.title_default');

  build() {
    Row() {
      ...
      Row() {
        Image($r('app.media.loading'))
          .height(TitleBarStyle.IMAGE_LOADING_SIZE)
          .width(TitleBarStyle.IMAGE_LOADING_SIZE)
          .onClick(() => {
            this.isRefreshData = !this.isRefreshData;
          })
      }
      .width(TitleBarStyle.WEIGHT)
      .height(WEIGHT)
      .justifyContent(FlexAlign.End)
    }
   ...
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

封装列表头部样式组件

在 ListHeaderComponent 文件中,我们使用常规成员变量来设置自定义组件 ListHeaderComponent 的 widthValue 和 paddingValue。

@Component
export struct ListHeaderComponent {
  paddingValue: Padding | Length;
  widthValue: Length;

  build() {
    Row() {
      Text($r('app.string.page_number'))
        .fontSize(FontSize.SMALL)
        .width(ListHeaderStyle.LAYOUT_WEIGHT_LEFT)
        .fontWeight(ListHeaderStyle.FONT_WEIGHT)
        .fontColor($r('app.color.font_description'))
      Text($r('app.string.page_type'))
        .fontSize(FontSize.SMALL)
        .width(ListHeaderStyle.LAYOUT_WEIGHT_CENTER)
        .fontWeight(ListHeaderStyle.FONT_WEIGHT)
        .fontColor($r('app.color.font_description'))
      Text($r('app.string.page_vote'))
        .fontSize(FontSize.SMALL)
        .width(ListHeaderStyle.LAYOUT_WEIGHT_RIGHT)
        .fontWeight(ListHeaderStyle.FONT_WEIGHT)
        .fontColor($r('app.color.font_description'))
    }
    .width(this.widthValue)
    .padding(this.paddingValue)
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

创建 ListItemComponent

为了体现@Prop 单向绑定功能,我们在 ListItemComponent 组件中添加了一个@Prop 修饰的字段 isSwitchDataSource,当通过点击改变 ListItemComponent 组件中 isSwitchDataSource 状态时,ListItemComponent 作为 List 的子组件,并不会通知其父组件 List 刷新状态。在代码中,我们使用@State 管理 ListItemComponent 中的 isChange 状态,当用户点击 ListItemComponent 时,ListItemComponent 组件中的文本颜色发生变化。我们使用条件渲染控制语句,创建的圆型文本组件。

@Component
export struct ListItemComponent {
  index: number;
  private name: Resource;
  @Prop vote: string;
  @Prop isSwitchDataSource: boolean;
  // 判断是否改变ListItemComponent字体颜色
  @State isChange: boolean = false;

  build() {
    Row() {
      Column() {
        if (this.isRenderCircleText()) {
          this.CircleText(this.index);
        } else {
          Text(this.index.toString())
            .lineHeight(ItemStyle.TEXT_LAYOUT_SIZE)
            .textAlign(TextAlign.Center)
            .width(ItemStyle.TEXT_LAYOUT_SIZE)
            .fontWeight(FontWeight.BOLD)
            .fontSize(FontSize.SMALL)
        }
      }
      .width(ItemStyle.LAYOUT_WEIGHT_LEFT)
      .alignItems(HorizontalAlign.Start)

      Text(this.name)
        .width(ItemStyle.LAYOUT_WEIGHT_CENTER)
        .fontWeight(FontWeight.BOLDER)
        .fontSize(FontSize.MIDDLE)
        .fontColor(this.isChange ? ItemStyle.COLOR_BLUE : ItemStyle.COLOR_BLACK)
      Text(this.vote)
        .width(ItemStyle.LAYOUT_WEIGHT_RIGHT)
        .fontWeight(FontWeight.BOLD)
        .fontSize(FontSize.SMALL)
        .fontColor(this.isChange ? ItemStyle.COLOR_BLUE : ItemStyle.COLOR_BLACK)
    }
    .height(ItemStyle.BAR_HEIGHT)
    .width(WEIGHT)
    .onClick(() => {
      this.isSwitchDataSource = !this.isSwitchDataSource;
      this.isChange = !this.isChange;
    })
  }
  ...
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

创建 RankList

为了简化代码,提高代码的可读性,我们使用@Builder 描述排行列表布局内容,使用循环渲染组件 ForEach 创建 ListItem。

...
  build() {
    Column() {
      // 顶部标题组件
      TitleComponent({ isRefreshData: $isSwitchDataSource, title: TITLE })
      // 列表头部样式
      ListHeaderComponent({
        paddingValue: {
          left: Style.RANK_PADDING,
          right: Style.RANK_PADDING
        },
        widthValue: Style.CONTENT_WIDTH
      })
        .margin({
          top: Style.HEADER_MARGIN_TOP,
          bottom: Style.HEADER_MARGIN_BOTTOM
        })
      // 列表区域
      this.RankList(Style.CONTENT_WIDTH)
    }
    .backgroundColor($r('app.color.background'))
    .height(WEIGHT)
    .width(WEIGHT)
  }

  @Builder RankList(widthValue: Length) {
    Column() {
      List() {
        ForEach(this.isSwitchDataSource ? this.dataSource1 : this.dataSource2,
          (item, index) => {
            ListItem() {
              ListItemComponent({ index: index + 1, name: item.name, vote: item.vote,
                isSwitchDataSource: this.isSwitchDataSource
              })
            }
          }, item => JSON.stringify(item))
      }
      .width(WEIGHT)
      .height(Style.LIST_HEIGHT)
      .divider({ strokeWidth: Style.STROKE_WIDTH })
    }
    .padding({
      left: Style.RANK_PADDING,
      right: Style.RANK_PADDING
    })
    .borderRadius(Style.BORDER_RADIUS)
    .width(widthValue)
    .alignItems(HorizontalAlign.Center)
    .backgroundColor(Color.White)
  }
...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

使用自定义组件生命周期函数

通过点击系统导航返回按钮来演示 onBackPress 回调方法的使用,在指定的时间段内,如果满足退出条件,onBackPress 将返回 false,系统默认关闭当前页面。否则,提示用户需要再点击一次才能退出,同时 onBackPress 返回 true,表示用户自己处理导航返回事件。

...
@Entry
@Component
struct RankPage {
  ...
  onBackPress() {
    if (this.isShowToast()) {
      prompt.showToast({ message: $r('app.string.prompt_text'), duration: TIME });
      this.clickBackTimeRecord = new Date().getTime();
      return true;
    }
    return false;
  }
  ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

总结

本项目主要学习了下列知识点,为下个项目做好铺垫。

  1. 条件渲染、循环渲染语法的使用。
  2. @State、@Prop、@Link 修饰器的使用。
  3. @Builder 修饰器的使用。
  4. 自定义组件生命周期函数 onBackPress 的调用。
声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号