HMRouter 是目前鸿蒙 Next 开发中非常热门的路由框架,它基于官方推荐的 Navigation 组件进行封装,通过注解和编译插件的方式,极大地简化了路由配置,并提供了原生 Navigation 所不具备的拦截器、生命周期管理等强大功能。对于想要彻底替代传统 Router,或者希望优雅地解决复杂页面跳转问题的开发者来说,HMRouter 是一个值得认真考虑的解决方案。

为什么说 HMRouter 是“最好用”的?

在 HarmonyOS 的官方体系中,主要有两套路由方案:老的 Router 和新的 Navigation 组件。官方已明确将 Navigation 作为未来演进的方向,但原生 Navigation 的配置比较繁琐,且缺少一些关键能力。

HMRouter 的价值在于它补全并增强了 Navigation,它提供的核心能力如下:

核心能力 主要优势
注解驱动,简化配置 使用 @HMRouter 注解标记页面,无需手动注册路由表,代码更简洁。
强大的拦截器机制 支持全局局部路由拦截,轻松实现登录校验、权限控制等业务逻辑。
灵活的生命周期管理 可自定义页面生命周期处理器 (IHMLifecycle),优雅地处理返回弹窗、二次退出等场景。
跨模块跳转 完美支持 HAR/HSP 模块间的页面跳转,是组件化/模块化开发的利器。
自定义转场动画 简化自定义动画配置,支持为特定页面配置独立的切换动画效果。
单例页面和弹窗 轻松将页面设置为单例模式或弹窗(Dialog)模式,应对特殊UI需求。

核心功能详解与实战

1. 环境配置与初始化

这是使用 HMRouter 的第一步,主要包括安装依赖和配置编译插件。

  1. 安装依赖:在终端中执行以下命令安装核心库和转场动画库。

    bash

    ohpm install @hadss/hmrouter
    ohpm install @hadss/hmrouter-transitions
  2. 配置编译插件:修改项目根目录的 hvigor/hvigor-config.json5 文件,添加依赖。

    json

    {
      "dependencies": {
        "@hadss/hmrouter-plugin": "^1.0.0-rc.10"
      }
    }

    然后,在 entry 或其他需要使用路由的模块的 hvigorfile.ts 中引入插件。

    typescript

    // entry/hvigorfile.ts (以Hap模块为例)
    import { hapTasks } from '@ohos/hvigor-ohos-plugin';
    import { hapPlugin } from '@hadss/hmrouter-plugin';
    
    export default {
      system: hapTasks,
      plugins: [hapPlugin()]
    };
  3. 初始化路由:在 EntryAbility 的 onCreate 中初始化 HMRouterMgr

    typescript

    // EntryAbility.ets
    import { HMRouterMgr } from '@hadss/hmrouter';
    
    export default class EntryAbility extends UIAbility {
      onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
        HMRouterMgr.init({
          context: this.context,
        });
      }
    }
  4. 定义路由入口:在首页中使用 HMNavigation 容器作为路由根视图。

    typescript

    // Index.ets
    import { HMNavigation, HMDefaultGlobalAnimator } from '@hadss/hmrouter';
    
    @Entry
    @Component
    struct Index {
      build() {
        Column() {
          HMNavigation({
            navigationId: 'mainNavigation', // 容器ID,需全局唯一
            options: {
              standardAnimator: HMDefaultGlobalAnimator.STANDARD_ANIMATOR,
              dialogAnimator: HMDefaultGlobalAnimator.DIALOG_ANIMATOR,
            }
          }) {
            // 首页内容,例如一个跳转按钮
            Button('跳转到登录页')
              .onClick(() => {
                HMRouterMgr.push({ pageUrl: 'LoginPage' });
              })
          }
        }
      }
    }
2. 页面定义与跳转传参

定义一个页面只需使用 @HMRouter 注解,然后通过 HMRouterMgr 进行跳转和传参。

typescript

// LoginPage.ets
import { HMRouter, HMRouterMgr } from '@hadss/hmrouter';

@HMRouter({ pageUrl: 'LoginPage' })
@Component
export struct LoginPage {
  @State params: object | null = null;

  aboutToAppear(): void {
    // 接收跳转传参
    this.params = HMRouterMgr.getCurrentParam() as object;
    console.info('接收到的参数: ' + JSON.stringify(this.params));
  }

  build() {
    Column() {
      Text('登录页面')
      Button('返回首页').onClick(() => {
        // 返回,并可携带参数
        HMRouterMgr.pop({ param: { result: '登录成功' } });
      })
    }
  }
}

在首页跳转时,可以这样传参并接收返回结果:

typescript

// 跳转并传参,同时接收返回结果
HMRouterMgr.push({
  pageUrl: 'LoginPage',
  param: { from: 'HomePage' }
}, {
  onResult(popInfo) {
    // popInfo.result 即为返回时携带的参数
    console.info('从登录页返回,结果:' + JSON.stringify(popInfo.result));
  }
});
3. 拦截器:实现登录校验

拦截器是 HMRouter 最强大的功能之一。下面通过一个全局登录拦截器展示其用法。

  1. 定义拦截器类:实现 IHMInterceptor 接口,并用 @HMInterceptor 注解标记,设置 global: true 使其成为全局拦截器。

    typescript

    // LoginInterceptor.ets
    import { HMInterceptor, HMInterceptorAction, HMInterceptorInfo, HMRouterMgr, IHMInterceptor } from '@hadss/hmrouter';
    import { User } from '../common/User'; // 假设的登录状态管理类
    
    @HMInterceptor({
      interceptorName: 'LoginInterceptor',
      priority: 9,        // 数字越大,优先级越高
      global: true        // true 表示全局拦截
    })
    export class LoginInterceptor implements IHMInterceptor {
      handle(info: HMInterceptorInfo): HMInterceptorAction {
        if (User.isLogin()) {
          // 已登录,继续执行跳转
          return HMInterceptorAction.DO_NEXT;
        } else {
          // 未登录,跳转到登录页,并拦截本次路由
          HMRouterMgr.push({
            pageUrl: 'LoginPage',
            skipAllInterceptor: true // 登录页本身不触发拦截,防止死循环
          });
          // 返回 DO_REJECT,阻止本次跳转
          return HMInterceptorAction.DO_REJECT;
        }
      }
    }

这样,任何通过 HMRouterMgr.push 的跳转都会先经过此拦截器,未登录时会被自动拦截并跳转到登录页。

4. 生命周期:处理返回弹窗

通过自定义生命周期,可以优雅地处理“用户两次返回退出应用”这类场景。

  1. 定义生命周期类:实现 IHMLifecycle 接口,并重写 onBackPressed 方法。

    typescript

    // ExitAppLifecycle.ets
    import { HMLifecycle, HMLifecycleContext, IHMLifecycle } from '@hadss/hmrouter';
    
    @HMLifecycle({ lifecycleName: 'ExitAppLifecycle' })
    export class ExitAppLifecycle implements IHMLifecycle {
      private lastTime: number = 0;
    
      onBackPressed(ctx: HMLifecycleContext): boolean {
        let currentTime = new Date().getTime();
        if (currentTime - this.lastTime > 1000) {
          // 第一次点击,或间隔超过1秒
          this.lastTime = currentTime;
          ctx.uiContext.getPromptAction().showToast({
            message: '再按一次退出应用',
            duration: 1000
          });
          return true; // 返回 true,表示消费了返回事件,不执行默认退出
        } else {
          return false; // 返回 false,执行默认退出
        }
      }
    }
  2. 绑定生命周期:在需要此功能的页面(如首页)的 @HMRouter 注解中通过 lifecycle 参数进行关联。

    typescript

    @HMRouter({
      pageUrl: 'MainPage',
      singleton: true,
      lifecycle: 'ExitAppLifecycle' // 绑定
    })
    @Component
    export struct MainPage {
      // ...
    }

总结与进阶方向

HMRouter 通过注解和编译时技术,将鸿蒙的路由配置变得前所未有的简单,同时补全了拦截、生命周期等关键能力,是构建大型、模块化鸿蒙应用的理想选择。

如果你想在项目中使用,可以参考以下官方资源:

  • 官方文档与源码:在 Gitee 上搜索 hadss/hmrouter,这里有详细的接口文档和示例代码。

  • 官方示例:华为官方也提供了 HMRouter Sample Code 供开发者参考。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐