小白必看 HarmonyOS Next HMRouter 轻松上手秘籍
媒介
HMRouter 作为 HarmonyOS 的页面跳转场景办理方案,聚焦办理应用内原生页面的跳转逻辑。
HMRouter 底层对体系 Navigation 举行封装,集成了 Navigation、NavDestination、NavPathStack 的体系能力,提供了可复用的路由拦截、页面生命周期、自界说转场动画,而且在跳转传参、额外的生命周期、服务型路由方面对体系能力举行了扩展。
目的是让开发者在开发过程中无需关注 Navigation、NavDestination 容器组件的相关细节及模板代码,屏蔽跳转时的判断逻辑,降低拦截器、自界说转场动画实现复杂度,更好的举行模块间解耦
对比
现在鸿蒙应用开发中,官方推出的路由方案有两个,分别是Router和Navigation。现在官方主要推荐的也是 Navigation。
业务场景NavigationRouter一多能力支持,Auto 模式自顺应单栏跟双栏显示不支持跳转指定页面pushPath & pushDestinationpushUrl & pushNameRoute跳转 HSP 中页面支持支持跳转 HAR 中页面支持支持跳转传参支持支持获取指定页面参数支持不支持传参范例传参为对象情势传参为对象情势,对象中暂不支持方法变量跳转效果回调支持支持跳转单例页面支持支持页面返回支持支持页面返回传参支持支持返回指定路由支持支持页面返回弹窗支持,通过路由拦截实现showAlertBeforeBackPage路由替换replacePath & replacePathByNamereplaceUrl & replaceNameRoute路由栈整理clearclear整理指定路由removeByIndexes & removeByName不支持转场动画支持支持自界说转场动画支持支持,动画范例受限屏蔽转场动画支持全局和单次支持 设置 pageTransition 方法 duration 为 0geometryTransition 共享元素动画支持(NavDestination 之间共享)不支持页面生命周期监听UIObserver.on(‘navDestinationUpdate’)UIObserver.on(‘routerPageUpdate’)获取页面栈对象支持不支持路由拦截支持通过 setInterception 做路由拦截不支持路由栈信息查询支持getState() & getLength()路由栈 move 操作moveToTop & moveIndexToTop不支持沉醉式页面支持不支持,需通过 window 设置设置页面标题栏(titlebar)和工具栏(toolbar)支持不支持模态嵌套路由支持不支持 但是原生的 Navigation 缺少了路由拦截、页面生命周期、自界说转场动画,而且在跳转传参、额外的生命周期、服务型路由。
因此 HMRouter 便是对此做出了拓展和加强。
学习目标
接下来,将通过这篇文章带领小搭档上手HMRouter的应用。
工程目录
新建完工程后,再新建一个 Cart 动态共享包模块
- 工程的目录名称是 study
- 入口模块是 entry
- cart 是 hsp 模块
设置情况
使用 ohpm 安装依赖
- ohpm install @hadss/hmrouter
- ohpm install @hadss/hmrouter-transitions
复制代码 编译插件设置
- 修改工程的hvigor/hvigor-config.json文件,加入路由编译插件
- {
- "dependencies": {
- "@hadss/hmrouter-plugin": "^1.0.0-rc.10"
- // 使用npm仓版本号
- }
- // ...其他配置
- }
复制代码 - 在使用到 HMRouter 的模块中引入路由编译插件,修改hvigorfile.ts
我们项目的模块无非是 Hap、Har 和 Hsp。对应你当前的模块是哪种范例,就使用对应的写法
- Hap
- // entry/hvigorfile.ts entry模块的hvigorfile.ts
- import { hapTasks } from "@ohos/hvigor-ohos-plugin";
- import { hapPlugin } from "@hadss/hmrouter-plugin";
- export default {
- system: hapTasks,
- plugins: [hapPlugin()], // 使用HMRouter标签的模块均需要配置,与模块类型保持一致
- };
复制代码 - Har
- import { harTasks } from "@ohos/hvigor-ohos-plugin";
- import { harPlugin } from "@hadss/hmrouter-plugin";
- export default {
- system: harTasks,
- plugins: [harPlugin()], // 使用HMRouter标签的模块均需要配置,与模块类型保持一致
- };
复制代码 - Hsp
- import { hspTasks } from "@ohos/hvigor-ohos-plugin";
- import { hspPlugin } from "@hadss/hmrouter-plugin";
- export default {
- system: hspTasks,
- plugins: [hspPlugin()], // 使用HMRouter标签的模块均需要配置,与模块类型保持一致
- };
复制代码
初始化路由框架
entry/src/main/ets/entryability/EntryAbility.ets
- export default class EntryAbility extends UIAbility {
- onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
- HMRouterMgr.init({
- context: this.context,
- });
- }
- }
复制代码 界说路由入口
entry/src/main/ets/pages/Index.ets
当前页面作为整个路由的根容器
- import { HMDefaultGlobalAnimator, HMNavigation } from "@hadss/hmrouter";
- import { AttributeUpdater } from "@kit.ArkUI";
- class MyNavModifier extends AttributeUpdater<NavigationAttribute> {
- initializeModifier(instance: NavigationAttribute): void {
- // instance.hideNavBar(true); // 先注释掉 否则看不见结果
- }
- }
- @Entry
- @Component
- export struct Index {
- modifier: MyNavModifier = new MyNavModifier();
- build() {
- // @Entry中需要再套一层容器组件,Column或者Stack
- Column() {
- // 使用HMNavigation容器
- HMNavigation({
- navigationId: 'mainNavigation', homePageUrl: 'MainPage',
- options: {
- standardAnimator: HMDefaultGlobalAnimator.STANDARD_ANIMATOR,
- dialogAnimator: HMDefaultGlobalAnimator.DIALOG_ANIMATOR,
- modifier: this.modifier
- }
- }) {
- Column({ space: 10 }) {
- Button("跳转到 登录页面")
- }
- }
- }
- .height('100%')
- .width('100%')
- }
- }
复制代码 模块内跳转
我们先演示跳转到当前模块中的某个页面。
HMRouter 默认指定了 页面貌录 为 entry/src/main/ets/components
我们在这个里新建一个组件 entry/src/main/ets/components/LoginPage.ets
- import { HMRouter } from "@hadss/hmrouter"
- @HMRouter({
- pageUrl: 'LoginPage',
- })
- @Component
- export struct LoginPage {
- build() {
- Column() {
- Button('登录页面')
- }
- .width("100%")
- .height("100%")
- .justifyContent(FlexAlign.Center)
- }
- }
复制代码 此时,回到首页中,举行点击跳转登录
- Button("跳转到 登录页面").onClick(() => {
- HMRouterMgr.push({ pageUrl: "LoginPage" });
- });
复制代码 路由传参
转达
- HMRouterMgr.push({ pageUrl: "LoginPage", param: { 数据 } });
复制代码 接收
- HMRouterMgr.getCurrentParam(HMParamType.all);
复制代码 指定编译目录
刚才的登录页面是存放到 components 目录下的,现实开发中,我们可以会通过 views来存放页面,所以这里来设置下
在项目根目录创建路由编译插件设置文件study/hmrouter_config.json(可选)
- {
- "scanDir": ["src/main/ets/views"]
- }
复制代码 然后重命名之前的文件夹名字 entry/src/main/ets/components 为 entry/src/main/ets/views
重新编译执行即可
模块之间跳转
刚才的演示是在同一个模块内举行的,现在我们来演示差异模块之间的跳转
演示的目标是 entry 模块跳转到 cart 模块
cart 模块设置编译插件
cart 是 hsp
cart/hvigorfile.ts
- import { hspTasks } from "@ohos/hvigor-ohos-plugin";
- import { hspPlugin } from "@hadss/hmrouter-plugin";
- export default {
- system: hspTasks,
- plugins: [hspPlugin()], // 使用HMRouter标签的模块均需要配置,与模块类型保持一致
- };
复制代码 新建购物详情页面
cart/src/main/ets/views/CartDetail.ets
- import { HMRouter } from "@hadss/hmrouter"
- @HMRouter({
- pageUrl: 'CartDetail',
- })
- @Component
- export struct CartDetail {
- build() {
- Column() {
- Button('我的是购物车详情页面')
- }
- .width("100%")
- .height("100%")
- .justifyContent(FlexAlign.Center)
- }
- }
复制代码 entry 模块引入 cart 模块
entry/oh-package.json5
- "dependencies": {
- "cart": "file:../cart"
- },
复制代码 首页中举行跳转
entry/src/main/ets/pages/Index.ets
- Button("跳转到 购物车详情页面").onClick(() => {
- HMRouterMgr.push({ pageUrl: "CartDetail" });
- });
复制代码 效果
跳转动画
我们可以在跳转页面的时候来指定跳转动画
分类两个步骤
界说动画
假设 A 跳转 B, 那么就是 B 使用动画,为了方便使用,可以在 B 页面界说动画
我们继续使用上面的例子
index 跳转到 CarDetail , 所以在 CarDetail 界说动画
cart/src/main/ets/views/CartDetail.ets
- @HMAnimator({ animatorName: "liveCommentsAnimator" })
- export class liveCommentsAnimator implements IHMAnimator {
- effect(enterHandle: HMAnimatorHandle, exitHandle: HMAnimatorHandle): void {
- // 入场动画
- enterHandle.start(
- (
- translateOption: TranslateOption,
- scaleOption: ScaleOption,
- opacityOption: OpacityOption
- ) => {
- translateOption.y = "100%";
- }
- );
- enterHandle.finish(
- (
- translateOption: TranslateOption,
- scaleOption: ScaleOption,
- opacityOption: OpacityOption
- ) => {
- translateOption.y = "0";
- }
- );
- enterHandle.duration = 500;
- // 出场动画
- exitHandle.start(
- (
- translateOption: TranslateOption,
- scaleOption: ScaleOption,
- opacityOption: OpacityOption
- ) => {
- translateOption.y = "0";
- }
- );
- exitHandle.finish(
- (
- translateOption: TranslateOption,
- scaleOption: ScaleOption,
- opacityOption: OpacityOption
- ) => {
- translateOption.y = "100%";
- }
- );
- exitHandle.duration = 500;
- }
- }
复制代码 使用动画
在 HMRouter 上使用
- @HMRouter({
- pageUrl: 'CartDetail',
- // 2 使用动画
- animator: "liveCommentsAnimator"
- })
- @Component
- export struct CartDetail {
- build() {
- Column() {
- Button('我的是购物车详情页面')
- }
- .width("100%")
- .height("100%")
- .justifyContent(FlexAlign.Center)
- }
- }
复制代码 效果
拦截器
拦截器可以分成 2 种,局部拦截器和全局拦截器
标志在实现了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 目标页面存在时,执行全局,发起页面和目标页面的拦截器;
拦截器执行顺序:
- 按照优先级顺序执行,不区分自界说大概全局拦截器,优先级雷同时先执行@HMRouter 中界说的自界说拦截器
- 当优先级一致时,先执行 srcPage>targetPage>global
srcPage 体现跳转发起页面。
targetPage 体现跳转竣事时展示的页面。
局部拦截器
局部拦截器只对单个页面生效。我们拿 登录页面来测试 从首页 跳转到登录页面,登录页面的拦截器便会触发
entry/src/main/ets/views/LoginPage.ets
界说拦截器
- @HMInterceptor({ interceptorName: "Loginterceptor", global: false })
- export class JumpInfoInterceptor implements IHMInterceptor {
- handle(info: HMInterceptorInfo): HMInterceptorAction {
- console.log("拦截器", JSON.stringify(info));
- // DO_NEXT 正常跳转
- // DO_REJECT 拒绝跳转
- return HMInterceptorAction.DO_NEXT;
- }
- }
复制代码 使用拦截器
- // 使用拦截器
- @HMRouter({
- pageUrl: 'LoginPage',
- interceptors: ['Loginterceptor']
- })
- @Component
- export struct LoginPage {
- build() {
- Column() {
- Button('登录页面')
- }
- .width("100%")
- .height("100%")
- .justifyContent(FlexAlign.Center)
- }
- }
复制代码 输出效果
- {
- "srcName": "HM_NavBar",
- "targetName": "LoginPage",
- "type": "push",
- "routerPathInfo": {
- "pageUrl": "LoginPage"
- },
- "context": {
- "instanceId_": 100000
- },
- "isSrc": false
- }
复制代码 全局拦截器
直接在 index 页面上使用
- aboutToAppear(): void {
- // 注册全局拦截器
- HMRouterMgr.registerGlobalInterceptor({
- interceptorName: "拦截器的名字",
- // 优先级
- priority: 1,
- // 拦截器
- interceptor: {
- // 处理函数
- handle(info: HMInterceptorInfo) {
- return HMInterceptorAction.DO_NEXT
- }
- }
- })
- }
复制代码 生命周期
- @HMLifecycle(lifecycleName, priority, global)
复制代码 标志在实现了 IHMLifecycle 的对象上,声明此对象为一个自界说生命周期处置惩罚器
- lifecycleName: string, 自界说生命周期处置惩罚器名称,必填
- priority: number, 生命周期优先级,数字越大优先级越高,非必填,默认为 9;
- global: boolean, 是否为全局生命周期,当设置为 true 时,所有页面生命周期事件会转发到此对象;默认为 false
生命周期触发顺序:
按照优先级顺序触发,不区分自界说大概全局生命周期,优先级雷同时先执行@HMRouter 中界说的自界说生命周期
我们可以继续在登录页面上测试对应的生命周期
entry/src/main/ets/views/LoginPage.ets
界说生命周期
- @HMLifecycle({ lifecycleName: 'LoginLifecycle' })
- export class PageDurationLifecycle implements IHMLifecycle {
- private time: number = 0;
- onShown(ctx: HMLifecycleContext): void {
- this.time = new Date().getTime();
- console.log("生命周期", JSON.stringify(ctx))
- }
- onHidden(ctx: HMLifecycleContext): void {
- const duration = new Date().getTime() - this.time;
- }
- }
复制代码 使用生命周期
- // 使用拦截器
- @HMRouter({
- pageUrl: 'LoginPage',
- interceptors: ['Loginterceptor'],
- lifecycle: "LoginLifecycle"
- })
- @Component
- export struct LoginPage {
- build() {
- Column() {
- Button('登录页面')
- }
- .width("100%")
- .height("100%")
- .justifyContent(FlexAlign.Center)
- }
- }
复制代码 完整生命周期
- export interface HMLifecycleContext {
- uiContext: UIContext;
- navContext?: NavDestinationContext;
- }
- export type HMLifecycleCallback = (ctx: HMLifecycleContext) => boolean | void;
- export interface IHMLifecycle {
- onPrepare?(ctx: HMLifecycleContext): void;
- onAppear?(ctx: HMLifecycleContext): void;
- onDisAppear?(ctx: HMLifecycleContext): void;
- onShown?(ctx: HMLifecycleContext): void;
- onHidden?(ctx: HMLifecycleContext): void;
- onWillAppear?(ctx: HMLifecycleContext): void;
- onWillDisappear?(ctx: HMLifecycleContext): void;
- onWillShow?(ctx: HMLifecycleContext): void;
- onWillHide?(ctx: HMLifecycleContext): void;
- onReady?(ctx: HMLifecycleContext): void;
- onBackPressed?(ctx: HMLifecycleContext): boolean;
- }
复制代码 页面组件和生命周期数据交互
生命周期实例中可以初始化对象,而且在UI组件中获取做为状态变量
- import {
- HMInterceptor,
- HMInterceptorAction,
- HMInterceptorInfo,
- HMLifecycle,
- HMLifecycleContext,
- HMRouter,
- HMRouterMgr,
- IHMInterceptor,
- IHMLifecycle
- } from '@hadss/hmrouter';
- // 定义拦截器
- @HMInterceptor({ interceptorName: 'Loginterceptor', global: false })
- export class JumpInfoInterceptor implements IHMInterceptor {
- handle(info: HMInterceptorInfo): HMInterceptorAction {
- console.log("拦截器", JSON.stringify(info))
- return HMInterceptorAction.DO_NEXT;
- }
- }
- @Observed
- export class ObservedModel {
- isLoad: boolean = false;
- }
- @HMLifecycle({ lifecycleName: 'LoginLifecycle' })
- export class PageDurationLifecycle implements IHMLifecycle {
- model: ObservedModel = new ObservedModel()
- onAppear(ctx: HMLifecycleContext): void {
- }
- }
- // 使用拦截器
- @HMRouter({
- pageUrl: 'LoginPage',
- interceptors: ['Loginterceptor'],
- lifecycle: "LoginLifecycle"
- })
- @Component
- export struct LoginPage {
- @State model: ObservedModel | null =
- (HMRouterMgr.getCurrentLifecycleOwner()?.getLifecycle() as PageDurationLifecycle).model;
- build() {
- Column() {
- Button('登录页面' + this.model?.isLoad)
- .onClick(() => {
- this.model!.isLoad = !this.model?.isLoad
- })
- }
- .width("100%")
- .height("100%")
- .justifyContent(FlexAlign.Center)
- }
- }
复制代码 小结
hmrouter 的官网文档还是挺零散的,需要联合文档配套学习使用
HMRouter 接口和属性列表
查看详情
HMRouterPlugin 编译插件使用阐明
查看详情
HMRouterTransitions 高阶转场动画使用阐明
查看详情
自界说模板使用阐明
查看详情
自界说转场动画使用阐明
查看详情
原生到原生页面跳转场景办理方案
查看详情
SampleCode
查看详情
更多示例
查看详情
FAQ
查看详情
原理先容
查看详情
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |