写点什么

基于 eTS 高效开发 HarmonyOS 课程类应用

  • 2022 年 7 月 15 日
  • 本文字数:5243 字

    阅读完需:约 17 分钟

基于eTS高效开发HarmonyOS课程类应用

随着 HarmonyOS 3.0 Beta 版的发布,API Version 8 新增了大批 JS/eTS API 接口,相信很多开发者已经迫不及待想体验基于 eTS 的 HamronyOS 应用开发。本期 Codelab,我们将基于 API Version 8 实现一个 HarmonyOS 课程类应用,帮助大家学习 eTS 的声明式 UI 描述、循环渲染、状态数据管理等机制,体验基于 eTS 的极简高效开发。


一、整体介绍

在课程类应用界面中,左侧为课程分类导航栏,右侧为各个类别的课程内容。当用户上下滑动右侧课程内容时,左侧导航栏会跳转至对应的课程分类。当用户点击左侧导航栏的课程分类时,会高亮显示点击的内容,且右侧课程内容会跳转至对应类别的课程列表。那么如何基于 eTS 高效实现这样一个 HarmonyOS 课程类应用?下面我们将从声明式 UI 描述、循环渲染数据、状态数据管理三个维度来解析。


1、声明式 UI 描述界面布局是 UI 界面的骨架,决定了应用界面的交互和视觉风格。本示例中我们将通过 eTS 的一系列基础组件以声明式方式进行组合和扩展,并采用接近自然语义的编程语法直观地描述 UI 界面,包括参数构造配置、属性配置、事件配置以及子组件配置等。相较于基于 Java 的命令式开发,eTS 采用更接近自然语义的声明式编程语法,让开发者可以更直观地描述 UI 界面,有效地降低了开发者的上手成本,极大程度地提升了 UI 界面的构建效率,实现极简高效开发。


2、循环渲染数据数据模型是 UI 界面的肉体,描述了界面中数据的静态特征、动态行为和约束条件。本示例中我们将通过 eTS 直观地定义界面中各个模块的数据模型,包含名称、标识、图片链接等,并根据数据模型写入对应的数据。最后使用 eTS 提供的循环渲染机制(ForEach)将写入的数据循环渲染至对应的界面中。相较于基于 Java 的命令式开发,eTS 在渲染数据时 UI 的更新不需要开发者使用代码主动刷新,而是交给框架层自动处理,开发者不必关心框架如何实现 UI 绘制和渲染,实现界面数据的高效渲染。


3、状态数据管理联动效果是 UI 界面的灵魂,实现了界面中布局与数据的动态交互,本示例中我们将使用 eTS 提供的状态数据管理机制通过装饰组件拥有的状态属性,当装饰的变量更改时,组件会重新渲染更新 UI 界面数据,从而实现联动效果。相较于基于 Java 的命令式开发,eTS 通过功能不同的装饰器给开发者提供了清晰的页面更新渲染流程和管道。开发者要做的就是定义数据与 UI 的映射关系,后面只需要通过状态装饰器监听数据的状态,UI 即可自动刷新,这极大地减轻了程序员对 UI 的维护工作。


以上就是实现课程类应用的核心原理,下面我们将为大家带来各部分的具体实现。


二、搭建界面布局


eTS 提供了多种布局方式,不仅保留了经典的弹性布局能力,也提供了列表、宫格、栅格布局和适应多分辨率场景开发的原子布局能力。如图 1 所示,本示例中整体布局使用 Row 沿水平方向布局容器,并设置背景颜色为白色,Row 内部嵌套 Scroll 及 List 容器分别作为应用界面的导航栏布局和课程内容布局,下面我们将为你一一道来。


图 1 整体布局


  1. 导航栏布局

应用界面的导航栏使用可滚动的容器组件 Scroll 来实现,Scroll 内嵌 Text 组件用于显示“课程分类”名称,如图 2 所示:


图 2 导航栏布局


Scroll 容器必须内置一个子组件,我们使用了垂直方向的布局容器 Column,并设置填充高度为 height('100%')。“课程分类”名称使用 Text 组件实现,并设置文字颜色为 fontColor(0x696969)、文字大小为 fontSize(16)、文字对齐方式为 textAlign(TextAlign.Center)居中显示、高度为 height(60)、宽度为 width('100%')。


相关代码如下:

Scroll() {  Column() {    ForEach(this.tabArray.map((item1, index1) => {      return { index: index1, data: item1 };    }), item => {      Text(item.data.superName)        .fontColor(0x696969)        .backgroundColor(this.index == item.index ? 0xffffff : null)        .fontSize(16)        .width('100%')        .height(60)        .textAlign(TextAlign.Center)        .onClick(() => {          if (this.index != item.index) {            this.index = item.index            this.scroller.scrollToIndex(item.data.position)          }        })    }, item => '' + item.data)  }.height('100%')}.width(100).height('100%').backgroundColor(0xdddddd).scrollBar(BarState.Off)
复制代码


  1. 课程内容布局

应用的课程内容部分的布局使用 List 列表容器来实现,并使用 ForEach 循环渲染 listArray(课程内容)数据,如图 3 所示,课程内容布局包含头部和课程信息两部分(头部和左边的导航栏对应),下面我们将分别介绍头部及课程信息的布局的实现。


图 3 课程内容布局


(1) 头部布局头部使用 Text 组件实现,并设置了文字颜色为 fontColor(0x696969)、文字大小为 fontSize(20)、高度为 height(40)、宽度为 width('100%')填充、内边距为 padding({ left: 10 })、背景颜色为 backgroundColor(0xefefef)。同时,头部的 ListItem 设置了 sticky(Sticky.Normal)属性,使其滑动到顶部时可以呈现固定的效果。代码如下:

if (item.tag) {  ListItem() {    Text(item.courseName)      .fontColor(0x696969)      .fontSize(20)      .height(40)      .width('100%')      .padding({ left: 10 })      .backgroundColor(0xefefef)  }.sticky(Sticky.Normal)
复制代码


(2) 课程信息布局

课程信息部分使用 Stack 堆叠容器,高度设置为 height(120),设置子组件在容器内的对齐方式为 Alignment.TopStart。Stack 组件内嵌 Image、Text、Divider 组件,用于呈现课程图片、课程标题、课程价格及分割线等信息。具体如下:●课程的图片使用 Image 组件呈现,设置宽度为 width(130),高度为 height(100),图片的缩放类型为 objectFit(ImageFit.Fill),使图片填充满组件,并设置左边、顶部边距均 10,使其组件居中对齐。代码如下:

Image(item.imageUrl)  .objectFit(ImageFit.Cover)  .width(130)  .height(100)  .margin({ left: 10, top: 10 })
复制代码


●课程名称使用 Text 组件,设置文字颜色为 fontColor(0x363636)、文字大小为 fontSize(14),最大显示行数为 maxLines(2)两行,文本超长时的显示方式为 TextOverflow.Clip,意为进行裁剪显示。代码如下:

Text(item.courseName)  .fontColor(0x363636)  .fontSize(14)  .margin({ left: 150, top: 12 })  .maxLines(2)  .textOverflow({ overflow: TextOverflow.Clip })
复制代码


●课程的价格使用 Text 组件,设置文字颜色为 fontColor(0xff6600)、文字大小为 fontSize(24),并使用了绝对定位 position({ x: 0, y: '100%' })先让组件显示在 Stack 容器最底部的外边界下,然后使用锚点定位 markAnchor({ x: 0, y: '100%' })使组件以自身高度向上偏移,让组件显示在 Stack 容器最底部。代码如下:

Text(item.price == 0 ? '免费' : '¥' + item.price)  .fontColor(0xff6600)  .fontSize(24)  .position({ x: 0, y: '100%' })  .markAnchor({ x: 0, y: '100%' })  .margin({ bottom: 18, left: 150 })
复制代码


●分割线使用 Divider 组件实现,并设置了分割线颜色为 color(0xefefef)、分割线宽度为 strokeWidth(0.7)、左右边距 margin({ left: 10, right: 10 })均为 10,并使用绝对定位 position({ x: 0, y: '100%' })和锚点定位 markAnchor({ x: 0, y: '100%' })使分割线呈现在 Stack 容器最底部。代码如下:

Divider()  .margin({ left: 10, right: 10 })  .color(0xefefef)  .strokeWidth(0.7)  .position({ x: 0, y: '100%' })  .markAnchor({ x: 0, y: '100%' })
复制代码


至此,我们已经实现了界面布局,此时界面只是一个没有任何内容的骨架。接下来我们将为应用界面添加数据模型。


三、构建数据模型

本章节我们将为大家介绍本示例中数据模型的定义、数据的预置以及数据的加载。


  1. 定义数据模型

本示例需定义两个数据模型,分别是应用界面中左侧导航栏的“课程分类”和右侧的“课程内容”。其中:● 导航栏“课程分类”定义了名称(superName)和位置(position)属性。数据模型定义如下:

export class TabItem {  position: number; // 点击该分类时课程内容滑动到的位置  superName: string; // 课程分类标题

constructor(position: number, superName: string) { this.position = position; this.superName = superName; }}
复制代码


● “课程内容”定义了课程的名称(courseName)、课程的图片地址(imageUrl)、课程的价格(price)、判断是否为此类别课程头部的变量(tag)、课程所对应课程类别的索引位置(index),数据模型定义如下:

export class CourseItem {  tag: boolean; // 是否此类别课程的头部  index: number; // 课程所对应课程类别的索引位置  courseName: string; // 课程名称  imageUrl: string; // 图片地址  price: number; // 价格  constructor(tag: boolean, index: number, courseName: string, imageUrl: string, price: number) {    this.tag = tag;    this.index = index;    this.courseName = courseName;    this.imageUrl = imageUrl;    this.price = price;  }}
复制代码


  1. 预置数据

在 entry/src/main/ets/MainAbility/Model.ets 文件中,放入准备好的模拟数据,其中,superId 是课程分类的唯一标识、id 是课程内容的唯一标识。格式如下:

const LinkData: any[] = [  {     "superId": 1,     "superName": "热门课程",     "id": 1,     "courseName": "应用市场介绍",     "imageUrl": "/image/image1.jpg",     "price": 0   }, {    "superId": 1,    "superName": "热门课程",    "id": 2,    "courseName": "上架流程",    "imageUrl": "/image/image2.jpg",    "price": 100  },  ... ]
复制代码


3.加载数据更新 UI

本章节将介绍如何加载本地构造的模拟数据并呈现到界面。

(1) 加载数据

在 index.ets 文件中,通过 getLinkData()获取预置数据。

aboutToAppear() {  // 延时数据加载  setTimeout(() => {    let linkDataItem = getLinkData();    this.tabArray = linkDataItem.tabArray;    this.listArray = linkDataItem.listArray;    this.requestSuccess = true;  }, 2000)}
复制代码


(2) 渲染

● 导航栏使用 ForEach 循环渲染 tabArray(课程分类)数据。这里的 ForEach 的第一个参数需要使用数组的 map()方法遍历。代码如下:

let superId: number = 0model.forEach((item) => {  if (superId != item.superId) {    let tabItem = new TabItem(this.listArray.length, item.superName);    this.tabArray.push(tabItem)

let courseItem = new CourseItem(true, this.tabArray.length - 1, item.superName, '', 0); this.listArray.push(courseItem) }})
复制代码


● 课程内容使用 ForEach 循环渲染 listArray(课程内容)数据。代码如下:

ForEach(this.listArray, item => {  if (item.tag) {    ListItem() {    ......    }.sticky(Sticky.Normal)  } else {    ListItem() {      Stack({ alignContent: Alignment.TopStart }) {      ......      }.height(120)    }  }}, item => '' + item)
复制代码


通过上文的介绍,我们已经实现了应用界面的布局以及界面数据的呈现,此时界面就像没有灵魂的躯壳。下面我们将为大家介绍应用中联动效果的实现。


四、实现界面联动

本示例中的联动效果包括导航栏高亮显示、滑动课程内容对应导航栏变化、点击导航栏课程分类跳转到对应课程内容,下面我们将一一道来。



  1. 导航栏高亮显示

实现导航栏高亮显示,主要通过 @State 装饰器监听导航栏课程分类的索引值的状态变化,当用户滑动课程内容或点击导航栏,对应课程分类的索引值发生变化,此时将调用 build 方法进行 UI 刷新,从而实现导航栏背景色的修改。相关代码如下:

@State index: number= 0; // 导航栏课程分类的索引Text(item.data.superName)  .backgroundColor(this.index == item.index ? 0xffffff : null)
复制代码


2.右边滑动,左边变化

滑动右边课程内容,对应左边导航栏变化,主要通过 onScrollIndex()事件来判断当前课程内容所属的课程分类,当用户滑动课程内容时,对应课程内容的索引值发生变化,导航栏的课程分类的索引值也随之变化。相关代码如下:

private scroller: Scroller = new Scroller()List({ scroller: this.scroller }) {  ......  }.onScrollIndex((firstIndex: number) => {  if (this.index != this.listArray[firstIndex].index) {    this.index = this.listArray[firstIndex].index  }})
复制代码


3.左边点击,右边跳转

点击左边导航栏跳转到对应课程内容,主要通过 onClick()事件监听用户点击,当用户点击导航栏,scrollToIndex()方法会根据点击的导航栏课程分类的索引值跳转到对应的课程内容界面。相关代码如下:

Text(item.data.superName)  .onClick(() => {    if (this.index != item.index) {      this.index = item.index      this.scroller.scrollToIndex(item.data.position)    }  })
复制代码


以上就是本期全部内容,通过本期 Codelab 的学习,相信你已经掌握了 eTS 的声明式 UI 描述、循环渲染、状态数据管理等机制,赶快趁热打铁,开发更多有趣的应用吧!



用户头像

每一位开发者都是华为要汇聚的星星之火 2021.10.15 加入

提供HarmonyOS关键技术解析、版本更新、开发者实践和活动资讯,欢迎各位开发者加入HarmonyOS生态,一起创造无限可能!

评论

发布
暂无评论
基于eTS高效开发HarmonyOS课程类应用_HarmonyOS_HarmonyOS开发者社区_InfoQ写作社区