当前位置: 首页 > news >正文

【HarmonyOS】HMRouter配置与基本使用

文章目录

  • 一、HMRouter简介
    • 1、概念
    • 2、特性
  • 二、依赖配置
    • 1、安装依赖
    • 2、编译插件配置
    • 3、工程配置
  • 三、初步探索
    • 1、初始化路由框架
    • 2、定义路由接口
    • 3、定义拦截器
    • 4、定义生命周期
    • 5、路由跳转使用
  • 四、标签分类
    • 1、 路由标签@HMRouter
    • 2、拦截器标签 @HMInterceptor
    • 3、生命周期标签 @HMLifecycle
  • 五、HMRouter接口和属性列表
    • 1、HMNavigation, 路由容器组件
      • 1.1 HMNavigationOption
    • 2、HMRouterMgr类
      • 2.1 HMRouterConfig类
      • 2.2 HMRouterPathInfo类
      • 2.3 HMRouterPathCallback类
      • 2.4 HMPopInfo类
      • 2.5 HMParamType枚举
      • 2.6 HMPageParam类
      • 2.7 HMPageInstance类
      • 2.8 HMPageLifecycle类
  • 六、部分案例介绍
    • 1、页面跳转与返回
    • 2、多次页面跳转,返回指定页面
    • 3、应用未登录,点击跳转登录页的校验场景
    • 4、实现单例页面的跳转
    • 5、实现弹窗类型的页面
    • 6、返回时弹窗,提示用户是否确认返回
    • 7、首页两次返回退出应用

一、HMRouter简介

开发者文档:HMRouter参考文档

1、概念

HMRouter的出现是为了解决页面跳转的问题,它对系统Navigation进行封装,集成了Navigation、NavDestination等的系统能力,提供了可复用的路由拦截、自定义转场动画,并且在跳转传参、额外的生命周期、服务型路由方面对系统能力进行了扩展。

2、特性

  1. 使用自定义注解实现路由跳转。
  2. 支持HAR,HSP,HAP。
  3. 支持路由拦截、路由生命周期。
  4. 简化自定义动画配置:配置全局动画,单独指定某个页面的切换动画。
  5. 支持不同的页面类型。

二、依赖配置

1、安装依赖

在终端中使用ohpm安装依赖。

ohpm install @hadss/hmrouter

在这里插入图片描述

如图,即为添加成功。同时上侧会出现蓝条,点击Sync now(立即同步)即可。

或者按需在模块中配置运行时依赖,修改oh-package.json5

{"dependencies": {"@hadss/hmrouter": "latest"}
}

2、编译插件配置

  1. 修改工程的hvigor/hvigor-config.json文件。

在这里插入图片描述

{"dependencies": {"@hadss/hmrouter-plugin": "latest"},// ...其他配置
}

同上点击Sync now即可。

  1. 在使用到HMRouter的模块中引入路由编译插件,修改hvigorfile.ts

在这里插入图片描述

import { hapTasks } from '@ohos/hvigor-ohos-plugin';
import { hapPlugin } from '@hadss/hmrouter-plugin';export default {system: hapTasks,plugins: [hapPlugin()]
}
// 使用HMRouter标签的模块均需要配置,与模块类型保持一致
// 如果模块是Har则使用harPlugin(), 模块是Hsp则使用hspPlugin(), 模块是Hap则使用hapPlugin()
  1. 项目根目录或者模块目录创建路由编译插件配置文件hmrouter_config.json(推荐)
{// 如果不配置则扫描src/main/ets目录,对代码进行全量扫描,如果配置则数组不能为空,建议配置指定目录可缩短编译耗时"scanDir": ["src/main/ets/components","src/main/ets/interceptors"],// 默认为false,调试排除错误时可以改成true,不删除编译产物"saveGeneratedFile": false,// 默认为false,不自动配置混淆规则,只会生成hmrouter_obfuscation_rules.txt文件帮助开发者配置混淆文件;如果设置为true,会自动配置混淆规则,并删除hmrouter_obfuscation_rules.txt文件"autoObfuscation": false,// 默认模板文件,不配置时使用插件内置模板"defaultPageTemplate": "./templates/defaultTemplate.ejs",// 特殊页面模版文件,匹配原则支持文件通配符"customPageTemplate": [{"srcPath": ["**/component/Home/**/*.ets"],"templatePath": "./templates/home_shopping_template.ejs"},{"srcPath": ["**/common/**/*.ets"],"templatePath": "./templates/common_template.ejs"},{"srcPath": ["**/live/**/*.ets"],"templatePath": "./templates/live_template.ejs"}]
}
customPageTemplate字段中srcPath使用标准文件通配符规则,相关符号描述如下* (星号):匹配任意数量的字符(包括零个字符),但不匹配路径分隔符(如 /)。例如,*.txt 可以匹配所有 .txt 结尾的文件。
** (双星号):匹配任意深度的目录或文件。可以用于递归搜索子目录。例如,**/*.js 可以匹配当前目录及其所有子目录中的所有 .js 文件。
/ (正斜杠):路径分隔符,用于分隔目录和文件名称。
! (感叹号):用于排除某些文件或目录,通常结合其他通配符使用。例如,!node_modules/** 可以排除 node_modules 目录及其子目录中的所有文件。
? (问号):匹配任意一个字符(不包括路径分隔符)。例如,file?.txt 可以匹配 file1.txt 或 fileA.txt,但不匹配 file123.txt。
[abc] (方括号):匹配方括号内的任意一个字符。例如,file[123].txt 可以匹配 file1.txt、file2.txt 或 file3.txt。
[!abc] (方括号加感叹号):匹配不在方括号内的任意一个字符。例如,file[!123].txt 可以匹配 fileA.txt,但不匹配 file1.txt、file2.txt 或 file3.txt。
{a,b,c} (大括号):匹配大括号中的任意一个模式。例如,*.{jpg,png,gif} 可以匹配 .jpg、.png 或 .gif 格式的文件。
\ (反斜杠):转义字符,用于匹配特殊字符本身。例如,如果要匹配文件名中带有 * 的文件,可以使用 * 进行转义。

hmrouter_config.json 配置

hmrouter_config.json文件用于配置该插件在编译期的行为。

配置文件读取规则为 模块 > 工程 > 默认

优先使用本模块内的配置,如果没有配置,则找模块目录的上级目录(最多找三层目录,找到则停止),若找不到则使用默认配置

1.0.0-rc.6 版本开始,支持混淆配置autoObfuscation

1.0.0-rc.9 版本开始,支持自定义模版配置customPageTemplate

配置项类型是否必填说明
scanDirarray指定扫描当前模块路径,默认值为src/main/ets
saveGeneratedFileboolean默认为 false,不保留插件自动生成的代码,如果需要保留,需要设置为 true
autoObfuscationboolean默认为 false,不自动配置混淆规则,只会生成hmrouter_obfuscation_rules.txt文件帮助开发者配置混淆规则;如果设置为 true,会自动配置混淆规则,并在编译完成后删除hmrouter_obfuscation_rules.txt文件
defaultPageTemplatestring默认模版路径,相对于hmrouter_config.json文件,例如:./templates/defaultTemplate.ejs
customPageTemplateobjectsrcPath为匹配的代码文件路径,支持通配符,templatePath为模版路径,可以实现不同的代码使用不同的模版来生成
  1. HMRouterPlugin 中,EJS模板用于生成动态页面或组件。

模板文件中至少需要包含NavDestination组件代码和相对应的build函数,缺少会导致编译失败或者页面白屏,插件中会内置一套默认模板,其中包含了页面展示、生命周期注册、转场动画注册

默认模板介绍

插件默认会根据如下模板来生成NavDestination页面代码,如有自定义模板的需求,建议先阅读内置模板的介绍在做更改,书写自定义模板时建议在内置模板基础上添加代码,删除内置模板相关代码可能会导致编译失败、生命周期生效、转场动画失效等问题

默认模版viewBuilder.ejs

import { <%= componentName %> } from '<%= importPath %>'
import { TemplateService, TranslateOption, ScaleOption, OpacityOption } from '@hadss/hmrouter'@Builder
export function <%= componentName %>Builder(name: string, param: Object) {<%= componentName %>Generated()
}@Component
export struct <%= componentName %>Generated {@State translateOption: TranslateOption = new TranslateOption()@State scaleOption: ScaleOption = new ScaleOption()@State opacityOption: OpacityOption = new OpacityOption()private pageUrl: string = '<%= pageUrl %>'private ndId: string = ''private navigationId: string = ''aboutToAppear(): void {this.navigationId = this.queryNavigationInfo()!.navigationId;TemplateService.aboutToAppear(this.navigationId, this.pageUrl, <%= dialog %>,this.translateOption, this.scaleOption, this.opacityOption)}aboutToDisappear(): void {TemplateService.aboutToDisappear(this.navigationId, this.pageUrl, this.ndId)}build() {NavDestination() {<%= componentName %>()}<% if(dialog){ %>.mode(NavDestinationMode.DIALOG)<% } %>.hideTitleBar(true).gesture(PanGesture().onActionStart((event: GestureEvent) => {TemplateService.interactiveStart(this.navigationId, this.ndId, event)}).onActionUpdate((event: GestureEvent) =>{TemplateService.interactiveProgress(this.navigationId, this.ndId, event)}).onActionEnd((event: GestureEvent) =>{TemplateService.interactiveFinish(this.navigationId, this.ndId, event)})).translate(this.translateOption).scale(this.scaleOption).opacity(this.opacityOption.opacity).onAppear(() => {TemplateService.onAppear(this.navigationId, this.pageUrl, this.ndId)}).onDisAppear(() => {TemplateService.onDisAppear(this.navigationId, this.pageUrl, this.ndId)}).onShown(() => {TemplateService.onShown(this.navigationId, this.pageUrl, this.ndId)}).onHidden(() => {TemplateService.onHidden(this.navigationId, this.pageUrl, this.ndId)}).onWillAppear(() => {TemplateService.onWillAppear(this.navigationId, this.pageUrl)}).onWillDisappear(() => {TemplateService.onWillDisappear(this.navigationId, this.pageUrl, this.ndId)}).onWillShow(() => {TemplateService.onWillShow(this.navigationId, this.pageUrl, this.ndId)}).onWillHide(() => {TemplateService.onWillHide(this.navigationId, this.pageUrl, this.ndId)}).onReady((navContext: NavDestinationContext) => {this.ndId = navContext.navDestinationId!TemplateService.onReady(this.navigationId, this.pageUrl, navContext)}).onBackPressed(() => {return TemplateService.onBackPressed(this.navigationId, this.pageUrl, this.ndId)})}
}

在这里插入图片描述

模板变量

属性描述
pageUrl标签中配置的pageUrl的值
importPath原组件的导入路径
componentName原组件名
dialog是否dialog页面
generatorViewName生成的文件名

TemplateService内置模版方法

该类中封装了一系列在模板中需要用到的注册、初始化、事件回调接口

接口参数返回值接口描述
static aboutToAppearnavigationId: string,pageUrl: string, dialog: boolean, translateOption: TranslateOption, scaleOption: ScaleOption, opacityOption: OpacityOptionvoid注册接口,用于模板代码中注册动画与生命周期
static aboutToDisappearnavigationId: string, pageUrl: string, ndId: stringvoid销毁,用户销毁一个页面的动画与生命周期实例
static onDisAppearnavigationId: string, pageUrl: string, navId: stringvoidNavDestination生命周期
static onAppearnavigationId: string, pageUrl: string, navId: stringvoidNavDestination生命周期
static onShownnavigationId: string, pageUrl: string, navId: stringvoidNavDestination生命周期
static onHiddennavigationId: string, pageUrl: string, navId: stringvoidNavDestination生命周期
static onWillAppearnavigationId: string, pageUrl: stringvoidNavDestination生命周期
static onWillDisappearnavigationId: string, pageUrl: string, navId: stringvoidNavDestination生命周期
static onWillShownavigationId: string, pageUrl: string, navId: stringvoidNavDestination生命周期
static onWillHidenavigationId: string, pageUrl: string, navId: stringvoidNavDestination生命周期
static onReadynavigationId: string, pageUrl: string, navContext: NavDestinationContextvoidNavDestination生命周期
static onBackPressednavigationId: string, pageUrl: string, navId: stringvoidNavDestination生命周期
static interactiveStartnavigationId: string, ndId: string, event: GestureEventvoid手势转场动画触发
static interactiveFinishnavigationId: string, ndId: string, event: GestureEventvoid手势转场动画更新
static interactiveProgressnavigationId: string, ndId: string, event: GestureEventvoid手势转场动画结束

3、工程配置

由于拦截器、生命周期和自定义转场动画会在运行时动态创建实例,因此需要进行如下配置,使得HMRouter路由框架可以动态导入项目中的模块

  1. 在工程目录下的build-profile.json5中,配置useNormalizedOHMUrl属性为true

在这里插入图片描述

原本是true就不用管了。

  1. oh-package.json5中配置对Har和Hsp的依赖,这里需要注意依赖的模块名称需要与module.json5moduleNameoh-package.json5name保持一致。

如果只是一个entry目录就不用管这个点。

三、初步探索

1、初始化路由框架

EntryAbilityonCreate初始化。

在这里插入图片描述

import { HMRouterMgr } from '@hadss/hmrouter';
    HMRouterMgr.init({context: this.context})

另一种方法可以参考:在启动框架中初始化

2、定义路由接口

HMRouter依赖系统Navigation能力,所以必须在页面中定义一个HMNavigation容器,并设置相关参数。

import { HMDefaultGlobalAnimator, HMNavigation, HMRouterMgr } from '@hadss/hmrouter';
import { AttributeUpdater, uiObserver } from '@kit.ArkUI';class MyNavModifier extends AttributeUpdater<NavigationAttribute> {initializeModifier(instance: NavigationAttribute): void {instance.hideNavBar(true);}
}@Entry
@Component
struct Index {modifier: MyNavModifier = new MyNavModifier();build() {// @Entry中需要再套一层容器组件,Column或者StackColumn() {// [Start hum_navigation] 使用HMNavigation容器HMNavigation({navigationId: 'mainNavigationId',homePageUrl: 'MainPage',options: {standardAnimator: HMDefaultGlobalAnimator.STANDARD_ANIMATOR,modifier: this.modifier}});// [End hum_navigation]}.height('100%').width('100%').expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]);}
}

Navigation的系统属性通过modifier传递,部分modifier不支持的属性使用options设置

3、定义拦截器

@HMInterceptor({ interceptorName: 'JumpInfoInterceptor', global: true })
export class JumpInfoInterceptor implements IHMInterceptor {handle(info: HMInterceptorInfo): HMInterceptorAction {let connectionInfo: string = info.type === 'push' ? 'jump to' : 'back to';Logger.info(`${info.srcName} ${connectionInfo} ${info.targetName}`)return HMInterceptorAction.DO_NEXT;}
}

4、定义生命周期

@HMLifecycle({ lifecycleName: 'PageDurationLifecycle' })
export class PageDurationLifecycle implements IHMLifecycle {private time: number = 0;onShown(ctx: HMLifecycleContext): void {this.time = new Date().getTime();}onHidden(ctx: HMLifecycleContext): void {const duration = new Date().getTime() - this.time;Logger.info(`Page ${ctx.navContext?.pathInfo.name} stay ${duration}`);}
}

5、路由跳转使用

使用@HMRouter标签定义页面,绑定拦截器、生命周期及自定义转场动画

@HMRouter({ pageUrl: '/pageB', lifecycle: 'pageLifecycle', animator: 'pageAnimator' })
@Component
export struct PageB {// 获取生命周期中定义的状态变量@State model: ObservedModel | null = (HMRouterMgr.getCurrentLifecycleOwner().getLifecycle() as PageLifecycle).model@State param: HMPageParam = HMRouterMgr.getCurrentParam(HMParamType.all)build() {Column() {Text(`${this.model?.property}`)Text(`${this.param.paramsMap?.get('msg')}`)}}
}

定义页面PageA,使用HMRouterMgr.push执行路由跳转至PageB

const PAGE_URL: string = '/pageA'@HMRouter({ pageUrl: PAGE_URL })
@Component
export struct PageA {build() {Column() {Button('Push').onClick(() => {HMRouterMgr.push({ pageUrl: 'pageB?msg=abcdef' })})}
}
}

路由跳转支持URL带参数的方式,例如定义的页面pageUrl: /pages1/users,跳转时可以指定pageUrl为: /pages1/users?msg=1234

通过 URL 参数的形式传递了数据 msg=abcdef

这里的 ? 是 URL 中分隔路径和参数的标识符,? 后面的部分 msg=abcdef 是传递的参数:

通过HMRouterMgr.getCurrentParam传入HMParamType.all获取URL的参数内容

// 假设在 pageB 中获取参数
const params = HMRouterMgr.getCurrentParams(HMParamType.all);
console.log(param.paramsMap?.get('msg')); // 输出: 1234

四、标签分类

1、 路由标签@HMRouter

@HMRouter(...) 标签使用在自定义组件struct上,且该自定义组件需要添加export关键字。

  • pageUrl: string, 用来表示NavDestination,必填
  • isRegex:boolean, 标识配置的pageUrl是否是正则表达式,非必填。
  • regexPriority: number, pageUrl正则匹配优先级,数字越大越先匹配,默认值为0,优先级相同时,不保证先后顺序,非必填,默认为0。
  • dialog: boolean, 是否是Dialog类型页面,非必填,默认为false。
  • singleton: boolean, 是否是单例页面,单例页面即表示在一个HMNavigation容器中,只有一个此页面,非必填,默认为false。
  • interceptors: string[], @HMInterceptor标记的拦截器名称列表,非必填。
  • lifecycle: string, @HMLifecycle标记的生命周期处理实例,非必填。
  • animator: string, @HMAnimator标记的自定义转场实例,非必填。

2、拦截器标签 @HMInterceptor

标记在实现了IHMInterceptor的对象上,声明此对象为一个拦截器。

  • interceptorName: string, 拦截器名称,必填
  • priority: number, 拦截器优先级,数字越大优先级越高,非必填,默认为9;
  • global: boolean, 是否为全局拦截器,当配置为true时,所有跳转均过此拦截器;默认为false,当为false时需要配置在@HMRouter的interceptors中才生效。

执行时机:

在路由栈发生变化前,转场动画发生前进行回调。 1.当发生push/replace路由时,pageUrl为空时,拦截器不会执行,需传入pageUrl路径;

2.当跳转pageUrl目标页面不存在时,执行全局以及发起页面拦截器,当拦截器未执行DO_REJECT时,然后执行路由的onLost回调

3.当跳转pageUrl目标页面存在时,执行全局,发起页面和目标页面的拦截器;

3、生命周期标签 @HMLifecycle

@HMLifecycle(lifecycleName, priority, global)

标记在实现了IHMLifecycle的对象上,声明此对象为一个自定义生命周期处理器。

  • lifecycleName: string, 自定义生命周期处理器名称,必填。
  • priority: number, 生命周期优先级,数字越大优先级越高,非必填,默认为9;
  • global: boolean, 是否为全局生命周期,当配置为true时,所有页面生命周期事件会转发到此对象;默认为false。

生命周期触发顺序:

按照优先级顺序触发,不区分自定义或者全局生命周期,优先级相同时先执行@HMRouter中定义的自定义生命周期。

五、HMRouter接口和属性列表

开发文档

1、HMNavigation, 路由容器组件

在这里插入图片描述

参数说明
navigationId需要开发者指定,并确保全局唯一,否则运行时输出报错日志
homePageUrl需要与@HMRouter(pageUrl)中的pageUrl一致,表示HMNavigation默认加载的页面。
navigationOption指定该HMNavigation的全局参数选项NavigationOption,保留可扩展性。

1.1 HMNavigationOption

参数说明
modifier:AttributeUpdaterNavigation动态属性设置
standardAnimator:IHMAnimator.Effect页面全局动画配置
dialogAnimator:IHMAnimator.Effect弹窗全局动画配置
title : NavTitle系统Title设置
menus: Array | CustomBuilder系统Menu设置
toolbar: Array | CustomBuilder系统Toolbar设置
systemBarStyle: Optional系统SystemBar设置

2、HMRouterMgr类

核心类,提供初始化方法,日志使能方法,路由能力

接口参数返回值接口描述
static initconfig: HMRouterConfigvoid初始化HMRouter,采用多线程初始化,将标签里面的页面与拦截器、转场动画、生命周期的映射加载到内存
static openLoglevel : ‘DEBUG’|‘INFO’void使能HMRouter日志。level为info时,表示打开Info日志,level为debug时,表示打开info和debug日志。论述是否调用openLog,warnning和error日志均正常打印。
static pushpathInfo: HMRouterPathInfo, callback? HMRouterPathCallbackvoid实现路由跳转,提供跳转回调
static replacepathInfo: HMRouterPathInfo, callback?: HMRouterPathCallbackvoid实现路由跳转,提供跳转回调
static poppathInfo?: HMRouterPathInfo, skipedLayerNumber?: numbervoid实现路由返回, skipedLayerNumber返回是跳跃的页面层数,默认为0(表示返回上级页面,1表示跳过一级页面返回,即同时两个页面出栈),以HMRouterPathInfo.pageUrl为首选,skipedLayerNumber为次选

2.1 HMRouterConfig类

初始化配置

参数说明
context:UIAbilityContextUIAbility上下文,用于初始化时读取路由配置信息
initWithTaskPool?: boolean是否使用taskpool进行多线程初始化,默认为开启

2.2 HMRouterPathInfo类

路由参数,用于路由跳转/返回参数。

参数说明
navigationId?根页面名称,对应的是Navigation的名称/ID,当navigationId为null时,表示为对最近一次navigation组件内进行路由跳转。
pageUrl?路由页面名称,对应的是NavDestination的名称,@HMRouter(pageUrl, isRegex, regexPriority, dialog, interceptor, animator, lifecycle)中的pageUrl,push时必须传入,否则会打印错误日志
param?传递的参数,当调用push时表示传递给下页面的参数对象,当调用pop时表示回传给上一页面的返回参数对象。
animator?自定义动画,传入使用此自定义动画执行转场,不再使用原先定义的转场。如果为false时,则不触发动画
interceptors?自定义拦截器,最高优先级执行。
lifecycle?自定义生命周期,最高优先级执行。
skipAllInterceptors?是否跳过所有拦截器,boolean类型

2.3 HMRouterPathCallback类

提供路由完成回调

参数说明
onResult页面返回回调,回调参数类型HMPopInfo
onArrival目标页面跳转完成回调
onLost目标页面找不到回调

onResult回调可以在每次返回该页面时触发

2.4 HMPopInfo类

参数说明
srcPageInfoname:返回的源页面,param: 源页面参数
info系统NavPathInfo对象
result返回携带的参数

2.5 HMParamType枚举

获取页面参数接口传参类型

枚举值说明
all接口返回HMPageParam对象,包含页面所有参数,HMPageParam.data为路由跳转时传入的param参数, HMPageParam.paramsMap为解析url路径参数,包含pathParam和queryParam内容
urlParam接口返回Map<string, Oject>对象,内容通过解析url获取,例如pageUrl定义/path/id,路由跳转时参数/path/id?name=xxx,则map包含name=123
routeParam接口返回Object对象,接口返回内容为路由时传入的HMRouterPathInfo的param对象

2.6 HMPageParam类

获取页面参数接口返回值类型

属性说明
dataObject或者null类型,为路由时传入的HMRouterPathInfo的param对象
urlParam接口返回Map<string, Object>对象,解析路由时pageUrl路径获取参数

2.7 HMPageInstance类

用于动态注册路由信息

参数说明
builder路由页面内容,需要使用NavDestination组件包裹,WrappedBuilder类型
pageUrl路由页面名称, 同@HMRouter pageUrl
interceptorArray?页面对应拦截器,同@HMRouter interceptors
singleton?页面是否单例,同@HMRouter singleton

2.8 HMPageLifecycle类

@Entry页面生命周期管理类

方法说明
onDisAppear页面销毁时触发,绑定页面销毁时回调
onShown页面显示时触发,绑定页面显示时回调
onHidden页面隐藏时触发,绑定页面隐藏时回调
onBackPressed页面侧滑返回时触发,绑定页面侧滑返回时回调

六、部分案例介绍

1、页面跳转与返回

HMRouter提供了基于自定义注解的页面跳转与返回功能,使用步骤如下:

  1. 为需要跳转的页面添加@HMRouter注解,并配置其中的pageUrl参数,例如此处配置为ProductContent。

    
    @HMRouter({ pageUrl: 'ProductContent' })
    @Component
    export struct ProductContent {// ...@State param: ParamsType | null = null;aboutToAppear(): void {this.param = HMRouterMgr.getCurrentParam() as ParamsType;}// ...
    }
    
  2. 在需要进行页面跳转的位置,使用HMRouterMgr提供的新版链式APIto方法进行页面跳转,在参数中配置目标页面的pageUrl,param参数等,例如下述代码配置pageUrl为ProductContent,并传递了相关参数。此处也可以配置页面栈唯一标识navigationId,当使用多个HMNavigation时建议开发者手动指定,当使用单个HMNavigation时,开发者可以不传递navigationId参数,系统会默认处理。同时HMRouter对to方法还做了增强,可以在后面拼接传递多个参数,在其中配置返回到当前页面时数据接受的回调函数onResult,只要有页面返回到该页面时都会触发该函数,该函数会接收一个参数,可以通过该参数上的srcPageInfo.name获取到由哪个页面跳转到当前页,还可以从该参数上的result属性获取到其他页面pop到当前页面时传递的参数。

    HMRouterMgr.to('ProductContent').withNavigation('mainNavigationId').withParam({ a: 1, b: 2 }).onResult((popInfo: HMPopInfo) => {const pageName = popInfo.srcPageInfo.name;const params = popInfo.result;console.log(`page name is ${pageName}, params is ${JSON.stringify(params)}`);}).pushAsync()
    
  3. 在跳转的目标页面使用HMRouterMgr.getCurrentParam()获取到传递的页面参数。

    @Component
    export struct ProductContent {// ...@State param: ParamsType | null = null;aboutToAppear(): void {this.param = HMRouterMgr.getCurrentParam() as ParamsType;}// ...
    }
    
  4. 如需使用页面返回功能,在对应的业务逻辑位置使用HMRouterMgr提供的pop方法实现页面返回,同样的pop方法支持传入navigationId,同时HMRouter还支持在返回时通过配置param参数向其所返回的页面传递参数。

    HMRouterMgr.pop({ navigationId: 'mainNavigationId', param: this.param })
    

2、多次页面跳转,返回指定页面

当页面跳转路径如HomePage->PageA->PageB->PageC,开发者希望在PageC的页面逻辑中直接返回到HomePage并携带参数,开发者仅需使用HMRouterMgr提供的pop方法,传入要返回目标页面的pageUrl、传递的参数param,即可直接带参返回到指定页面。

HMRouterMgr.to('MainPage')  .withNavigation('mainNavigationId')  .withParam(0)  .pushAsync()

图1 返回指定页面示意图
点击放大

3、应用未登录,点击跳转登录页的校验场景

应用中经常会有当用户未登录应用时,点击某些应用内容会自动跳转到登录页面的场景,在使用HMRouter对此场景进行实现时,可以采用以下步骤:

  1. 定义拦截器类LoginCheckInterceptor实现IHMInterceptor接口。

  2. 为定义的拦截器类添加@HMInterceptor注解,通过interceptorName配置拦截器名称LoginCheckInterceptor。

  3. 实现IHMInterceptor的intercept异步拦截器方法,在该方法中根据当前的登录状态来控制页面跳转的目标。

    1. 当用户已登录,通过执行chain.onContinue(),正常执行后续页面跳转逻辑。

    2. 当用户未登录,通过Toast弹窗向用户提示登录,然后跳转到登录页面,最后通过执行chain.onIntercept()来拦截此次跳转请求。

      @HMInterceptor({ interceptorName: 'LoginCheckInterceptor' })
      export class LoginCheckInterceptor implements IHMInterceptor {async intercept(chain: IHMInterceptorChain): Promise<void> {const info = chain.getRouterInfo();const context = chain.getContext();// ...if (!!AppStorage.get('isLogin')) {await chain.onContinue()} else {info.context.getPromptAction().showToast({ message: '请先登录' });HMRouterMgr.push({pageUrl: 'loginPage',skipAllInterceptor: true});await chain.onIntercept();}// ...}
      }
      
  4. 在需要进行拦截的页面中配置@HMRouter的interceptors参数即可,由于一个页面可以配置多个拦截器,所以需要将关联的拦截器名称封装为一个数组进行传入。

运行效果如下图所示。

在这里插入图片描述

4、实现单例页面的跳转

当应用中存在初始化加载资源消耗大且有复用需求的页面时,就可以使用单例页面。典型的业务场景如视频类应用中的视频播放页面,此类页面通常需要加载视频解码器资源并对其初始化,且该页面在视频类应用中会频繁出现。实现上开发者只需要配置@HMRouter注解参数中的singleton参数为true即可。

@HMRouter({  pageUrl: 'liveHome',  singleton: true,  animator: 'liveInteractiveAnimator',  lifecycle: 'liveHomeLifecycle'})@Componentexport struct LiveHome {  // ...}

5、实现弹窗类型的页面

在HMRouter路由框架中,开发者只需要设置@HMRouter注解的dialog配置为true即可将当前页面作为弹窗使用。

@HMRouter({ pageUrl: 'privacyDialog', dialog: true })
@Component
export struct PrivacyDialogContent {// ...
}

6、返回时弹窗,提示用户是否确认返回

当从某些页面返回时,应用希望通过弹窗方式让用户确认是否要执行返回操作,例如在订单支付页面中用户执行返回操作时,通常会弹窗提示用户是否确认退出,当用户点击确认后才会执行页面退出逻辑,此场景下就可以考虑使用弹窗类型页面加上自定义生命周期来实现。操作步骤如下:

  1. 开发者首先需要根据自己的业务需求,来进行自定义弹窗的开发。

    @HMRouter({ pageUrl: 'PayCancel', dialog: true,animator:'PayCancelDialog' })
    @Component
    export struct PayCancel {// ...build() {Stack({ alignContent: Alignment.Center }) {ConfirmDialog({title: '取消订单',content: '您确认要取消此订单吗?',leftButtonName: '再看看',rightButtonName: '取消订单',leftButtonFunc: () => {HMRouterMgr.popAsync({navigationId: this.queryNavigationInfo()?.navigationId});},rightButtonFunc: () => {// ...}});}.width('100%').height('100%').position({x: '50%',y: '50%'}).markAnchor({x: '50%',y: '50%'});}
    }
    
  2. 定义ExitPayLifecycle类来实现IHMLifecycle接口,为ExitPayLifecycle加上@HMLifecycle注解,传入生命周期名称ExitPayLifecycle,在类的内部,重写onBackPressed回调函数,当用户执行返回操作时,该回调函数触发,弹出刚刚定义的PayCancel弹窗。

    @HMLifecycle({ lifecycleName: 'ExitPayLifecycle' })export class ExitPayLifecycle implements IHMLifecycle {  model: ObservedModel = new ObservedModel();onBackPressed(): boolean {    HMRouterMgr.to('PayCancel')      .withParam(this.model.pageUrl)      .pushAsync()    return true;  }}
    
  3. 将定义的生命周期与支付页面绑定,只需要将刚刚定义的生命周期传入对应组件@HMRouter注解的lifecycle参数即可。

    @HMRouter({  pageUrl: 'PayDialogContent',  dialog: true,  lifecycle: 'ExitPayDialog',  interceptors: ['LoginCheckInterceptor']})@Componentexport struct PayDialogContent {  // ...}
    

运行效果如下图所示。

点击放大

7、首页两次返回退出应用

该场景下用户第一次触发应用返回退出时向用户提示“再次返回退出”,第二次用户触发返回操作时应用真正退出。实现上可参考以下步骤:

  1. 定义一个生命周期类ExitAppLifecycle实现IHMLifecycle接口。

  2. 使用@HMLifecycle注解传入生命周期名称参数lifecycleName为ExitAppLifecycle。

  3. 重写其中的onBackPressed方法(此处是由于上述业务场景需要,实际开发中根据实际业务场景按需重写方法),通过判断上次返回操作与当前返回操作的时间间隔,按如下逻辑处理:

    1. 当两次返回操作的时间间隔大于设置值时(此处为1000ms),重新弹窗对用户进行提示,此处返回true,表示不执行默认返回逻辑。

    2. 当两次返回操作的时间间隔小于设置值时(此处为1000ms),返回为false表示执行默认返回逻辑,退出应用。

      @HMLifecycle({ lifecycleName: 'ExitAppLifecycle' })
      export class ExitAppLifecycle implements IHMLifecycle {private lastTime: number = 0;onBackPressed(ctx: HMLifecycleContext): boolean {let time = new Date().getTime();if (time - this.lastTime > 1000) {this.lastTime = time;ctx.uiContext.getPromptAction().showToast({message: 'Return to exit the application again.',duration: 1000});return true;} else {return false;}}
      }
      
  4. 将定义好的生命周期类与页面进行关联,开发者只需在@HMRouter注解中配置lifecycle为要关联的生命周期名称即可。

运行效果如下图所示。

img

http://www.dtcms.com/a/392721.html

相关文章:

  • 数据驱动下的实验设计与方差分析:从技术落地到方法论升维
  • 深度学习中的池化、线性层与激活函数
  • 【脑电分析系列】第22篇:EEG情绪识别与脑机接口(BCI)应用案例:机器学习与深度学习的实战
  • 深度学习知识点
  • 【pdf】如何将网页转换为pdf?
  • 家庭劳务智能机器人:从“科幻设想”到“推门而入”还有多远?
  • C++后台开发工具链实战
  • PortAudio--Cross-platform Open-Source Audio I/O Library
  • Oracle根据日期进行查询
  • 【C#】C# 中 `ProcessStartInfo` 详解:启动外部进程
  • Python快速入门专业版(三十六):Python列表基础:创建、增删改查与常用方法(15+案例)
  • 微服务项目->在线oj系统(Java-Spring)----5.0
  • 【读书笔记】《鲁迅传》
  • Python 基础:列表、字符串、字典和元组一些简单八股
  • C++ 运算符重载:类内与类外重载详解
  • 【java】jsp被截断问题
  • 在Windows10 Edge浏览器里安装DeepSider大模型插件来免费使用gpt-4o、NanoBanana等AI大模型
  • 车联网网络安全:技术演进与守护智能出行
  • 网络原理-传输层补充1
  • Amber `rism1d` 深度解析与实战教程
  • vscode在断点旁边写expression让条件为true的时候才触发断点提高调试效率
  • 何时使用RESETLOGS
  • 分布式链路追踪关键指标实战:精准定位服务调用 “慢节点” 全指南(一)
  • vaapi硬解码性能评估
  • 第 N 个泰波那契数
  • 面试经典150题[037]:矩阵置零(LeetCode 73)
  • mysql 简单操作
  • Maven:Java项目的自动化构建工具
  • 嵌入式硬件工程师每日提问
  • 2025年AI写小说工具测评:AI写作软件大比拼