
HMRouter 是目前鸿蒙生态中功能最完善的路由框架它封装了系统 Navigation 的复杂细节用注解方式让页面跳转变得简单高效。本文将带你从零开始全面掌握 HMRouter 的配置、跳转、拦截、生命周期等核心能力。一、为什么是 HMRouter在 HarmonyOS 中官方提供了两种路由方案Router和Navigation。Router 是早期的页面路由方案存在 32 条页面栈上限、不支持路由拦截等限制官方已不再推荐使用 。Navigation 是当前官方主推的组件化导航方案功能更强大但在实际开发中仍有一些痛点每个页面都需要手动包裹NavDestination增加代码层级缺少统一的路由拦截机制页面生命周期管理需要自行实现跨模块跳转配置繁琐HMRouter正是为解决这些问题而生。它在底层封装了 Navigation 的系统能力提供了一套基于注解的声明式路由方案让开发者几乎无需关心 Navigation 的复杂细节 。HMRouter 核心能力一览能力说明 注解驱动HMRouter声明页面路径HMInterceptor定义拦截器 跨模块跳转完美支持 HAR/HSP 之间的页面跳转 路由拦截支持全局/局部拦截器可实现登录校验、权限控制 页面生命周期自定义生命周期处理器监听页面事件✨ 自定义转场动画支持页面级和全局转场动画配置 单例页面通过singleton: true实现页面复用 Dialog 页面将页面以弹窗形式展示 返回传参支持页面返回时携带参数二、快速上手从零配置 HMRouter2.1 安装依赖首先安装 HMRouter 核心库bashohpm install hadss/hmrouter如果需要使用自定义转场动画还需安装过渡动画库bashohpm install hadss/hmrouter-transitions2.2 配置编译插件修改工程根目录的hvigor/hvigor-config.json添加路由编译插件依赖 json{ dependencies: { hadss/hmrouter-plugin: ^1.0.0-rc.10 } }然后在使用 HMRouter 的模块entry/har/hsp的hvigorfile.ts中引入插件entry 模块Haptypescript// entry/hvigorfile.ts import { hapTasks } from ohos/hvigor-ohos-plugin; import { hapPlugin } from hadss/hmrouter-plugin; export default { system: hapTasks, plugins: [hapPlugin()] };Har 模块使用harPlugin()Hsp 模块使用hspPlugin()2.3 工程配置在build-profile.json5中配置useNormalizedOHMUrl为true使框架能动态导入模块 json{ buildOption: { useNormalizedOHMUrl: true } }2.4 初始化路由框架在EntryAbility的onCreate中初始化HMRouterMgrtypescript// entry/src/main/ets/entryability/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 }); } }2.5 定义路由入口在首页中使用HMNavigation作为路由容器 typescript// entry/src/main/ets/pages/Index.ets import { HMDefaultGlobalAnimator, HMNavigation, HMRouterMgr } from hadss/hmrouter; import { AttributeUpdater } from kit.ArkUI; class NavModifier extends AttributeUpdaterNavigationAttribute { initializeModifier(instance: NavigationAttribute): void { instance.mode(NavigationMode.Stack); instance.hideTitleBar(true); instance.hideToolBar(true); } } Entry Component export struct Index { modifier: NavModifier new NavModifier(); build() { Column() { HMNavigation({ navigationId: mainNavigation, options: { standardAnimator: HMDefaultGlobalAnimator.STANDARD_ANIMATOR, dialogAnimator: HMDefaultGlobalAnimator.DIALOG_ANIMATOR, modifier: this.modifier } }) { // 首页内容 Button(跳转到登录页) .onClick(() { HMRouterMgr.push({ pageUrl: LoginPage }); }) } } .height(100%) .width(100%) } }2.6 创建第一个页面使用HMRouter注解声明页面 typescript// entry/src/main/ets/views/LoginPage.ets import { HMRouter } from hadss/hmrouter; HMRouter({ pageUrl: LoginPage }) Component export struct LoginPage { build() { Column() { Text(登录页面) Button(返回) .onClick(() { HMRouterMgr.pop(); }) } .width(100%) .height(100%) .justifyContent(FlexAlign.Center) } }注意事项HMRouter装饰的组件必须使用export导出默认页面目录为src/main/ets/components可通过hmrouter_config.json的scanDir自定义三、页面跳转与传参3.1 基础跳转typescript// push压栈跳转保留当前页面 HMRouterMgr.push({ pageUrl: ProductDetail }); // replace替换当前页面 HMRouterMgr.replace({ pageUrl: ProductDetail }); // pop返回上一页 HMRouterMgr.pop(); // pop 返回并携带参数 HMRouterMgr.pop({ param: { success: true } });3.2 跳转传参发送方typescriptHMRouterMgr.push({ pageUrl: ProductDetail, param: { productId: 12345, title: 华为Mate 60 } });接收方typescriptHMRouter({ pageUrl: ProductDetail }) Component export struct ProductDetail { State productId: string ; State title: string ; aboutToAppear(): void { const param HMRouterMgr.getCurrentParam(); if (param) { this.productId param.productId; this.title param.title; } } }3.3 页面返回结果回调跳转时注册onResult回调接收返回页面的数据 typescriptHMRouterMgr.push({ pageUrl: EditProfile, param: { userId: 123 } }, { onResult: (popInfo: HMPopInfo) { const fromPage popInfo.srcPageInfo.name; const result popInfo.result; console.log(从 ${fromPage} 返回数据${JSON.stringify(result)}); // 处理返回数据如刷新页面 } });返回页发送数据typescript// 在 EditProfile 页面中 HMRouterMgr.pop({ param: { updated: true, newName: 张三 } });3.4 返回指定页面在复杂跳转链路中如 A → B → C → D可直接返回到指定页面并传参 typescript// 从 D 页面直接返回到 A 页面 HMRouterMgr.pop({ navigationId: mainNavigation, pageUrl: HomePage, // 目标页面路径 param: { from: DetailPage, action: back } });3.5 跨模块跳转HMRouter 完美支持 HAR/HSP 模块间的跳转。假设cart模块需要跳转到entry模块的页面 1. 在 cart 模块的hvigorfile.ts中配置编译插件typescript// cart/hvigorfile.ts import { hspTasks } from ohos/hvigor-ohos-plugin; import { hspPlugin } from hadss/hmrouter-plugin; export default { system: hspTasks, plugins: [hspPlugin()] };2. entry 模块依赖 cart 模块json// entry/oh-package.json5 { dependencies: { cart: file:../cart } }3. 在 cart 模块中定义页面typescript// cart/src/main/ets/views/CartDetail.ets HMRouter({ pageUrl: CartDetail }) Component export struct CartDetail { // ... }4. entry 模块跳转typescriptHMRouterMgr.push({ pageUrl: CartDetail });四、路由拦截器登录校验与权限控制拦截器是 HMRouter 最强大的功能之一可在跳转前执行业务逻辑常用于登录校验、权限验证、埋点统计等场景 。4.1 定义拦截器实现IHMInterceptor接口使用HMInterceptor注解 typescriptimport { HMInterceptor, IHMInterceptor, HMInterceptorAction, HMInterceptorInfo } from hadss/hmrouter; HMInterceptor({ interceptorName: LoginCheckInterceptor }) export class LoginCheckInterceptor implements IHMInterceptor { handle(info: HMInterceptorInfo): HMInterceptorAction { // 检查登录状态 const isLogin AppStorage.getboolean(isLogin) ?? false; if (isLogin) { // 已登录继续跳转 return HMInterceptorAction.DO_NEXT; } else { // 未登录提示并跳转到登录页 info.context.getPromptAction().showToast({ message: 请先登录 }); HMRouterMgr.push({ pageUrl: LoginPage, skipAllInterceptor: true // 登录页跳过拦截防止死循环 }); // 拒绝原始跳转 return HMInterceptorAction.DO_REJECT; } } }4.2 使用拦截器局部拦截器仅对指定页面生效typescriptHMRouter({ pageUrl: ShoppingCart, interceptors: [LoginCheckInterceptor] // 数组形式支持多个 }) Component export struct ShoppingCart { // ... }全局拦截器对所有跳转生效typescriptHMInterceptor({ interceptorName: GlobalLoggerInterceptor, global: true, // 全局拦截器 priority: 10 // 优先级数字越大越先执行 }) export class GlobalLoggerInterceptor implements IHMInterceptor { handle(info: HMInterceptorInfo): HMInterceptorAction { console.log([路由] 从 ${info.srcPage} 跳转到 ${info.targetName}); return HMInterceptorAction.DO_NEXT; } }4.3 拦截器执行顺序按priority降序执行数字越大越优先同一优先级下执行顺序为发起页面拦截器 → 目标页面拦截器 → 全局拦截器五、页面生命周期管理HMRouter 提供了比系统更丰富的生命周期回调通过HMLifecycle注解定义生命周期处理器 。5.1 定义生命周期typescriptimport { HMLifecycle, IHMLifecycle, HMLifecycleContext } from hadss/hmrouter; HMLifecycle({ lifecycleName: PageLifecycle }) export class PageLifecycle implements IHMLifecycle { // 页面显示时触发 onShown(ctx: HMLifecycleContext): void { console.log(页面显示); } // 页面隐藏时触发 onHidden(ctx: HMLifecycleContext): void { console.log(页面隐藏); } // 返回键按下时触发返回 true 表示拦截false 表示执行默认返回 onBackPressed(ctx: HMLifecycleContext): boolean { console.log(用户按下返回键); return false; // 执行默认返回 } // 页面即将出现 onWillAppear(ctx: HMLifecycleContext): void { console.log(页面即将出现); } // 页面即将消失 onWillDisappear(ctx: HMLifecycleContext): void { console.log(页面即将消失); } }5.2 绑定生命周期typescriptHMRouter({ pageUrl: HomePage, lifecycle: PageLifecycle // 关联生命周期处理器 }) Component export struct HomePage { // ... }5.3 典型场景两次返回退出应用typescriptHMLifecycle({ lifecycleName: ExitAppLifecycle }) export class ExitAppLifecycle implements IHMLifecycle { private lastTime: number 0; onBackPressed(ctx: HMLifecycleContext): boolean { const now new Date().getTime(); if (now - this.lastTime 1000) { this.lastTime now; ctx.uiContext.getPromptAction().showToast({ message: 再次返回退出应用 }); return true; // 拦截本次返回 } return false; // 执行返回退出应用 } }在首页绑定该生命周期即可实现双击返回退出功能 。六、自定义转场动画6.1 定义页面动画使用HMAnimator注解定义动画类 typescriptimport { HMAnimator, IHMAnimator, HMAnimatorHandle } from hadss/hmrouter; HMAnimator({ animatorName: SlideUpAnimator }) export class SlideUpAnimator implements IHMAnimator { effect(enterHandle: HMAnimatorHandle, exitHandle: HMAnimatorHandle): void { // 入场动画从底部滑入 enterHandle.start((translate: any) { translate.y(100%).y(0); }, { duration: 300 }); // 出场动画滑到底部 exitHandle.start((translate: any) { translate.y(0).y(100%); }, { duration: 300 }); } }6.2 使用动画在目标页面的HMRouter中指定动画 typescriptHMRouter({ pageUrl: DetailPage, animator: SlideUpAnimator // 使用自定义动画 }) Component export struct DetailPage { // ... }6.3 全局默认动画在HMNavigation的options中配置全局动画 typescriptHMNavigation({ navigationId: mainNavigation, options: { standardAnimator: HMDefaultGlobalAnimator.STANDARD_ANIMATOR, dialogAnimator: HMDefaultGlobalAnimator.DIALOG_ANIMATOR, // ... } })七、高级特性7.1 单例页面当页面初始化开销较大且需要频繁复用时如视频播放页可配置为单例模式 typescriptHMRouter({ pageUrl: LivePlayer, singleton: true // 页面栈中只有一个实例 }) Component export struct LivePlayer { // ... }7.2 Dialog 页面将页面以弹窗形式展示 typescriptHMRouter({ pageUrl: PrivacyDialog, dialog: true }) Component export struct PrivacyDialog { build() { Stack({ alignContent: Alignment.Center }) { Column() { Text(隐私协议弹窗) // ... } .backgroundColor(Color.White) .borderRadius(16) .padding(20) } .width(100%) .height(100%) .backgroundColor(rgba(0,0,0,0.5)) } }7.3 指定页面扫描目录默认扫描src/main/ets/components可通过配置文件自定义 在项目根目录创建hmrouter_config.jsonjson{ scanDir: [src/main/ets/views, src/main/ets/pages] }八、最佳实践与常见问题8.1 最佳实践统一管理页面路径常量typescript// constants/PageConstants.ets export class PageConstants { static readonly HOME HomePage; static readonly LOGIN LoginPage; static readonly PRODUCT_DETAIL ProductDetail; }合理使用拦截器层级全局拦截器处理通用逻辑埋点、日志局部拦截器处理页面特定逻辑表单校验。避免拦截器死循环在拦截器跳转登录页时务必设置skipAllInterceptor: true。模块化开发每个独立功能模块HSP/HAR独立配置编译插件实现模块间解耦 。8.2 常见问题Q跳转时提示页面未找到A检查HMRouter的pageUrl是否与跳转时一致确认页面在扫描目录下默认components或配置scanDir。QHAR 模块中的页面无法跳转A确保 HAR 模块的hvigorfile.ts中配置了harPlugin()并在宿主模块的oh-package.json5中依赖该 HAR 。Q如何调试路由跳转A可配合系统NavPathStack的getAllPathName()方法查看当前页面栈。九、参考资源HMRouter Gitee 仓库官方示例代码接口文档FAQ 常见问题HMRouter 原理介绍HMRouter 通过注解驱动和插件化编译的方式极大地简化了 HarmonyOS 应用的路由管理。无论是基础的页面跳转、跨模块通信还是复杂的拦截器、生命周期管理HMRouter 都能提供优雅的解决方案。建议在新项目中直接采用 HMRouter可以显著提升路由相关的开发效率。