目录
前言
一、准备工作
二、实战开发
2.2、页面路由开发
2.2.1、创建常量
2.2.2、创建字符串资源
2.2.3、创建float资源
2.2.4、创建color资源
2.2.5、创建数据实体
2.2.6、创建页面路由表
2.2.9、页面路由跳转及传参
2.2.10、处理页面返回键
前言
写这个系列的目标是准备通过几篇文章的介绍,和大家一起快速入门HarmonyOS应用的开发。初步打算是主要通过代码实战的形式去介绍,基本的语法和使用还是建议大家先阅读官网的文档说明。OK,话不多说,咱们开始。
一、准备工作
首先,最全面的学习资料肯定是官网文档,所以需要快速掌握文档的对应位置,这里把开发中经常用到文档入口都罗列在下面了,按需自取:
开发指南 API文档 最佳实践 FAQ 示例代码
其次,注意搜索时左侧菜单可以选择类别,比如这里可以勾选全部:
OK,接着咱们下载开发工具:下载与安装DevEco Studio,这个没什么好说的,下载完了之后一步一步安装即可。
接着学习开发语言可以参考如下内容,鸿蒙中使用的ArkTS是基于TypeScript做了扩展:
学习ArkTS语言和应用框架中的ArkTs(方舟编程语言)
准备工作就做到这里,接下来就可以上手开发了,今天咱们首先来学习路由如何使用。
二、实战开发
2.1、Navigation简介
Navigation主要用于实现Navigation页面(NavDestination)间的跳转,支持在不同Navigation页面间传递参数,提供灵活的入栈出栈操作,方便快捷的实现对不同页面的访问和复用。关于Navigation更多的介绍及详细使用大家可以参考:
组件导航(Navigation) (推荐)
2.2、页面路由开发
首先我们先创建一个空工程,这里可以根据公司规范或者个人习惯修改相关文件名。在src/main/ets/pages目录下新建navigation文件夹,将Index.ets移动到该文件夹下,并修改文件名为NavigationPage.ets,并且修改代码中Index名称为NavigationPage,同时还需要修改EntryAbility文件中默认加载的页面路径:
上面的NavigationPage作为整个工程页面路由栈的根页面,你可以把它理解为一个相册,我们使用@Entry来修饰它,并且使用Navigation作为它的组件树的根节点。然后我们需要实现的APP的各个展示页面就是相册里面的一张一张的照片,我们使用@Component来修饰它,并且使用NavDestination作为它们的组件树的根节点。简单理解就是:Navigation是容器,NavDestination是页面。在今天的例子中,我们会创建两个页面MainPage和OtherPage。
今天由于是本系列的第一篇,所以一些基础工作我也会介绍一下,后续的文章中将不再赘述。
2.2.1、创建常量
在工程的src/main/ets 目录下新建文件夹constants,用来存放项目中需要用到的常量字段,这里我们创建两个文件:CommonConstant存放公共常量,PageConstant存放页面名称,代码如下:
export class CommonConstant {static readonly FULL_PERCENT: string = '100%'static readonly PAGEINFO_KEY: string = 'PageInfo'static readonly EXIT_INFO: string = '再按一次退出应用'static readonly PRE_TIME: number = 0static readonly EXIT_TIME: number = 2000
}
export class PageConstant{static readonly PAGE_MAIN: string = 'MainPage'static readonly PAGE_OTHER: string = 'OtherPage'
}
2.2.2、创建字符串资源
在resources/base/elment/string.json文件中添加项目中需要用到的字符串资源:
{"string": [{"name": "tip_main_page","value": "我是主页点我跳转"},{"name": "tip_other_page","value": "我是其它页面"}]
}
2.2.3、创建float资源
在resources/base/elment/float.json文件中添加项目中需要用到的字体大小fp和组件大小vp资源:
{"float": [{"name": "fp_20","value": "20fp"},{"name": "vp_100","value": "100vp"}]
}
2.2.4、创建color资源
在resources/base/elment/color.json文件中添加项目中需要用到的颜色资源:
{"color": [{"name": "color_primiry","value": "#57BE6A"}]
}
2.2.5、创建数据实体
在src/main/ets下新建model文件夹,在该文件夹下新建DemoData.ets文件,在这个文件里我们创建页面间传值所需的数据类,这里介绍了两种方式interface和class,都可以定义所需的实体:
// MainPage传递参数的数据类
export interface ParamData {name: string
}// OtherPage回传的数据类
export class BackData {result?: stringconstructor(result: string) {this.result = result}
}
2.2.6、创建页面路由表
在src/main/ets/pages/navigaion目录下新建PagesMapBuilder.ets文件,作为项目的页面路由表:
import { PageConstant } from "../../constants/PageConstant";
import { MainPage } from "../MainPage";
import { OtherPage } from "../OtherPage";@Builder
export function PagesMapBuilder(name: string) {if (name===PageConstant.PAGE_MAIN) {MainPage()}else if (name===PageConstant.PAGE_OTHER){OtherPage()}
}
2.2.7、创建Navigation根容器
在NavigationPage页面中,我们实例化了一个NavPathStack对象:
// 页面路由栈
@Provide(CommonConstant.PAGEINFO_KEY) pageStack: NavPathStack = new NavPathStack()
从名字也能看出它是用来管理页面路由的路由栈对象,这里我们使用了@Provide这个装饰器来修饰,它一般是与@Consume成对使用,用于与后代组件的双向数据同步、状态数据在多个层级之间传递的场景。使用详情可以参考:@Provide装饰器和@Consume装饰器:与后代组件双向同步
然后在build()函数中,我们创建Navigation组件并且绑定导航控制器和页面路由表:
import { CommonConstant } from '../../constants/CommonConstant'
import { PagesMapBuilder } from './PagesMapBuilder'@Entry
@Component
struct NavigationPage {// 页面路由栈@Provide(CommonConstant.PAGEINFO_KEY) pageStack: NavPathStack = new NavPathStack()build() {Navigation(this.pageStack).hideTitleBar(true).hideToolBar(true).hideNavBar(true).mode(NavigationMode.Stack).navDestination(PagesMapBuilder)}
}
这里的build()函数是用于定义自定义组件的声明式UI描述,自定义组件必须定义build()函数。从这里也就看出了HarmonyOS应用的UI是使用的声明式UI,这里提到了它是用于自定义组件的UI描述,因此咱们这里的NavigationPage也是自定义组件,你可以理解在HarmonyOS应用中:一切皆组件!
关于自定义组件的使用可以参考:创建自定义组件
可以看到,我们代码中的@Component struct正是符合这个结构的,至于最上面的@Entry,那是因为它装饰的自定义组件是UI页面的入口。
2.2.8、创建NavDestination子页面
在src/main/ets/pages文件夹下新建MainPage.ets文件,在这个文件中首先定义路由栈对象,承接上文中的@Provide,这里我们可以直接使用@Consume来定义:
@Consume(CommonConstant.PAGEINFO_KEY) pageStack: NavPathStack
然后在build()函数中创建NavDestination为根节点的组件树,这里面我们仅添加一个Text文本用于展示:
import { CommonConstant } from "../constants/CommonConstant"@Component
export struct MainPage {@Consume(CommonConstant.PAGEINFO_KEY) pageStack: NavPathStack@State content: string | Resource = $r('app.string.tip_main_page')build() {NavDestination() {Column() {Text(this.content).fontSize($r('app.float.fp_20')).fontColor(Color.Blue).fontWeight(FontWeight.Bold)}.width(CommonConstant.FULL_PERCENT).height(CommonConstant.FULL_PERCENT).justifyContent(FlexAlign.Center)}.hideTitleBar(true)}
}
这里的@State同样是一个状态管理的装饰器,用它修饰的变量在组件内数据变更时可以引起UI的自动刷新,具体使用可以参考:@State装饰器:组件内状态
然后以同样的方式创建另一个页面OtherPage.ets:
import { CommonConstant } from "../constants/CommonConstant"@Component
export struct OtherPage {@Consume(CommonConstant.PAGEINFO_KEY) pageStack: NavPathStack@State content: string | Resource = $r('app.string.tip_other_page')build() {NavDestination() {Column() {Text(this.content).fontSize($r('app.float.fp_20')).fontColor(Color.Blue).fontWeight(FontWeight.Bold).onClick(() => {let backData = new BackData('我是Other数据')this.pageStack.pop(backData)})}.width(CommonConstant.FULL_PERCENT).height(CommonConstant.FULL_PERCENT).justifyContent(FlexAlign.Center)}.hideTitleBar(true)}
}
2.2.9、页面路由跳转及传参
首先在NavigationPage的aboutToAppear()回调中添加第一个加载的页面视图:
aboutToAppear(): void {this.pageStack.pushPath({ name: PageConstant.PAGE_MAIN }, false)
}
aboutToAppear()是自定义组件的一个生命周期函数,在组件即将出现时回调该接口,具体时机为在创建自定义组件的新实例后,在执行其build函数之前执行,详情可以参考:
自定义组件生命周期
然后在MainPage中创建需要传递的参数:
paramData: ParamData = { name: '我是MainPage数据' }
在MainPage中的Text文本的点击事件里,跳转到OtherPage页面,并将上面的数据作为参数传递过去,同时在onPop回调中可以接收OtherPage页面回传的参数,如果不需要回传参数onPop回调可以不用写:
.onClick(() => {// 页面跳转,传递参数到Other页面,并通过onPop回调接收Other页面回传的数据this.pageStack.pushPath({name: PageConstant.PAGE_OTHER, param: this.paramData, onPop: (popInfo: PopInfo) => {let backData = popInfo.result as BackDatathis.content = backData.result}})})
接着在OtherPage页面中接收来自MainPage传递的参数,这里接收参数我们介绍两种方式:
第一种:使用NavDestination的onReady()函数进行接收:
.onReady((context: NavDestinationContext) => {this.paramData = context.pathInfo.param as ParamDataif (this.paramData) {this.content = this.paramData.name}})
第二种:在aboutToAppear()生命周期函数中通过pageStack的getParamByIndex()函数接收:
aboutToAppear(): void {this.paramData = this.pageStack.getParamByIndex(this.pageStack.size() - 1) as ParamDataif (this.paramData) {this.content = this.paramData.name}}
然后在OtherPage的Text文本的点击事件中我们将需要回传的参数通过pageStack的pop(xxx)方法进行回传:
.onClick(() => {let backData = new BackData('我是Other数据')this.pageStack.pop(backData)})
2.2.10、处理页面返回键
在Android中我们经常可以看到在点击Back键时会提示:再按一次退出应用,虽然现在很多手机隐藏了返回键,但是我们通过侧滑仍然可以出发页面返回,那如果想要实现上面的效果该怎么做呢?
其实原理是类似的,在HarmonyOS中,我们可以监听页面的onBackPress()事件,在这个函数中处理连续点按退出应用的逻辑:
import { CommonConstant } from '../../constants/CommonConstant'
import { common } from '@kit.AbilityKit'@Entry
@Component
struct NavigationPage {private context = this.getUIContext().getHostContext() as common.UIAbilityContextprivate preTime: number = CommonConstant.PRE_TIMEpromptAction = this.getUIContext().getPromptAction()// 2秒内连续点按/侧滑后关闭当前应用onBackPress(): boolean | void {let currentTime = new Date().getTime()let flag = currentTime - this.preTimeif (flag > CommonConstant.EXIT_TIME) {this.preTime = currentTimethis.promptAction.showToast({ message: CommonConstant.EXIT_INFO })return true} else {this.context.terminateSelf()}return false}
}
最后来看一下实现的效果吧:
实现效果录屏
完整代码:HarmonyDemos
OK,今天的内容到这里就要和大家说再见了,咱们下期再会!
祝:工作顺利,前程似锦!