HarmonyOS快速上手
近一段时间HarmonyOS热度高涨,也跟风看一下文档,做一下HarmonyOS快速上手的内容记录。
目录结构
在不使用云开发的情况下,基本目录结构如下:
AppScope- 存放应用全局所需要的资源文件entry- 应用主模块,存放代码、资源等main- 总文件夹ets- 存放ets代码entryability- 存放ability文件,用于应用逻辑和生命周期管理pages- 存放UI界面相关代码文件
resources- 存放多媒体和布局文件module.json5- 模块配置文件
ohosTest- 单元测试目录build-profile.json5- 模块级配置信息,包括编译、构建配置项hvigorfile.ts- 模块级构建脚本oh-package.json5- 模块级依赖配置文件
oh_modules- 工程依赖build-profile.json5- 工程级配置信息,包括签名、产品配置等hvigorfile.ts- 工程级编译构建任务脚本oh-package.json5- 工程级依赖配置文件
需要描述
UI的界面使用.ets文件其他的普通文件如
ability, 云服务等使用.ts文件。
组件与装饰器
组件分类
- 基础组件
- 容器组件
- 媒体组件
- 绘制组件
- 画布组件
比如Text, Image, Button等就是基础组件,我们在构建页面的时候,最外层要使用布局组件来进行包裹,常用的布局组件有Row, Column, List, Grid。
组件都是通过属性和方法来构建其样式和绑定事件的,布局组件和包含子组件的组件,使用{}包裹起内部组件。
1 | // 构建组件的装饰器,先不关注,只看内容 |
Row, Column就是用来构建Flex布局,比较简单,不过多赘述了,简单看一下List, Grid组件吧。
List一般与子组件ListItem配合使用,实现垂直/水平方向线性排列
List是很常用的滚动类容器组件,一般和子组件ListItem一起使用,List列表中的每一个列表项对应一个ListItem组件。
1 | List(value?: {space?: number | string, initialIndex?: number, scroller?: Scroller}) |
滚动事件监听:
onScroll- 滑动时触发,返回值scrollOffset为滑动偏移量,scrollState为当前滑动状态onScrollIndex- 滑动时触发,返回值为滑动起始位置索引和滑动结束位置索引onReachStart- 到达起始位置时触发onReachEnd- 到达末尾时触发onScrollStop- 滑动停止时触发
Grid组件为网格容器,是一种网格列表,由“行”和“列”分割的单元格所组成,通过指定“项目”所在的单元格做出各种各样的布局。Grid组件一般和子组件GridItem一起使用,Grid列表中的每一个条目对应一个GridItem组件。
1 | Grid() { |
构建的网格布局如果使用了固定的行数和列数,那么构建出的网格是不可滚动的。然而有时候因为内容较多,我们通过滚动的方式来显示更多的内容,就需要一个可以滚动的网格布局。我们只需要设置
rowsTemplate和columnsTemplate中的一个即可(要指定固定的高度或者宽度)。
装饰器
常用的装饰器有如下几个:
@Component- 自定义组件,必须实现build方法@Entry- 组件作为页面的默认入口组件@State- 装饰组件内部的状态数据,变化后自动触发更新@Prop- 装饰的变量必须使用父组件的@State进行初始化,组件内部修改后不会通知父组件,是单向数据绑定@Link- 装饰的变量可以和父组件的@State变量建立双向绑定,并且需要在父组件中进行初始化@Builder- 装饰的方法用于定义组件的声明式UI描述。@Provider/@Consume
组件状态
在组件范围传递的状态管理常见的场景如下:
| 场景 | 装饰器 |
|---|---|
| 组件内的状态管理 | @State |
| 从父组件单向同步状态 | @Prop |
| 与父组件双向同步状态 | @Link |
| 跨组件层级双向同步状态 | @Provide, @Consume |
如果需要观察嵌套类对象属性变化,需要使用
@Observed和@ObjectLink装饰器,因为上述表格中的装饰器只能观察到对象的第一层属性变化。当状态改变,需要对状态变化进行监听做一些相应的操作时,可以使用
@Watch装饰器来修饰状态
父子组件通信
前边说到的@Prop装饰器可以接收父组件传递的@State装饰的数据,但是有些时候没这么复杂,我们只是想在子组件接收父组件传递的数据进行渲染,可以直接定义属性
1 | // 子组件 |
生命周期
自定义组件
对于@Component定义的自定义组件生命周期为:
- 组件创建
aboutToAppear()- 创建组件之后,执行build之前 - 可以做一些数据初始化的工作aboutToDisappear()- 释放资源,清除副作用- 组件销毁
1 |
|
入口组件
对于使用@Entry修饰的页面入口组件还有额外的三个生命周期函数:
- 组件创建
aboutToAppear()onPageShow()- 页面显示onBackPress()- 返回onPageHide()- 页面消失aboutToDisappear()- 组件销毁
1 |
|
条件/循环渲染
使用if / else if / else进行条件渲染:
1 | build() { |
三元运算符也可以使用
使用ForEach迭代数组,为每个数组项创建组件
1 | RankList() { |
ForEach接收三个参数:
- 数组数据
- 组件生成函数
- 唯一键生成函数
路由
假设pages目录下有以下两个文件:
Index.etsSecond.ets
最常用的我们可以使用pushUrl进行路由的跳转,会将新的路由页面加入到栈中。
1 | // Index.ets |
1 | // Second.ets |
其他常用的路由跳转方法还有如
replaceUrl()等在返回之前还可以先调用
router.enableBackPageAlert()方法开启页面返回询问对话框功能。路由跳转模式:
Standard- 多实例模式,也是默认情况下的跳转模式。目标页面会被添加到页面栈顶,无论栈中是否存在相同url的页面。Single- 单实例模式。如果目标页面的url已经存在于页面栈中,则该url页面移动到栈顶。
UIAbility
UIAbility生命周期
UIAbility StartCreate- 实例创建时触发,系统会调用onCreate回调WindowStageCreate- 实例创建完成之后,在进入Foreground之前。WindowStage为本地窗口管理器,用于管理窗口相关的内容,例如与界面相关的获焦/失焦、可见/不可见。可以在onWindowStageCreate回调中,设置UI页面加载、设置WindowStage的事件订阅。Foreground- UIAbility切换至前台Background- UIAbility切换至后台WindowStageDestroy- 在UIAbility实例销毁之前,则会先进入onWindowStageDestroy回调,我们可以在该回调中释放UI页面资源。Destroy- 在UIAbility销毁时触发。可以在onDestroy回调中进行系统资源的释放、数据的保存等操作。UIAbility End
UIAbility生命周期包括四个状态:
CreateForegroundBackgroundDestroy
注意是UIAbility的状态
启动模式
UIAbility启动模式:
- 单实例模式
singleton- 默认情况下的启动模式。每次调用startAbility()方法时,如果应用进程中该类型的UIAbility实例已经存在,则复用系统中的UIAbility实例。系统中只存在唯一一个该UIAbility实例,即在最近任务列表中只存在一个该类型的UIAbility实例。 - 多实例模式
multiton- 每次调用startAbility()方法时,都会在应用进程中创建一个新的该类型UIAbility实例。即在最近任务列表中可以看到有多个该类型的UIAbility实例。 - 指定实例模式
specified- 针对一些特殊场景使用(例如文档应用中每次新建文档希望都能新建一个文档实例,重复打开一个已保存的文档希望打开的都是同一个文档实例)
在module.json5文件中的“launchType”字段配置
网络请求
需要在
module.json5中申明网络访问权限。
使用方式:
- 导入http模块
1 | import http from '@ohos.net.http'; |
- 创建httpRequest
1 | let httpRequest = http.createHttp(); |
每一个HttpRequest对象对应一个HTTP请求。如需发起多个HTTP请求,须为每个HTTP请求创建对应HttpRequest对象。最多只能创建100个HttpRequest对象。
- 订阅头信息(可选)
用于订阅http响应头,会比request请求先返回,如果有需要可以订阅
1 | httpReqquest.on('headersReceive', (header) => { |
- 发送http请求
1 | let url = 'https://xxxxx'; |
post请求的参数需要添加到extraData中:
1 | httpRequest.request( |
- 处理响应
1 | promise.then(data => { |
每一个httpRequest对应一个HTTP请求任务,不可复用