HarmonyOS NEXT 最强路由管理 HMRouter 完全指南
HMRouter 是目前鸿蒙生态中功能最完善的路由框架,它封装了系统 Navigation 的复杂细节,用注解方式让页面跳转变得简单高效。本文将带你从零开始,全面掌握 HMRouter 的配置、跳转、拦截、生命周期等核心能力。
一、为什么是 HMRouter?
在 HarmonyOS 中,官方提供了两种路由方案:Router 和 Navigation。Router 是早期的页面路由方案,存在 32 条页面栈上限、不支持路由拦截等限制,官方已不再推荐使用 。Navigation 是当前官方主推的组件化导航方案,功能更强大,但在实际开发中仍有一些痛点:
-
每个页面都需要手动包裹
NavDestination,增加代码层级 -
缺少统一的路由拦截机制
-
页面生命周期管理需要自行实现
-
跨模块跳转配置繁琐
HMRouter 正是为解决这些问题而生。它在底层封装了 Navigation 的系统能力,提供了一套基于注解的声明式路由方案,让开发者几乎无需关心 Navigation 的复杂细节 。
HMRouter 核心能力一览
| 能力 | 说明 |
|---|---|
| 📍 注解驱动 | @HMRouter 声明页面路径,@HMInterceptor 定义拦截器 |
| 🔀 跨模块跳转 | 完美支持 HAR/HSP 之间的页面跳转 |
| 🚦 路由拦截 | 支持全局/局部拦截器,可实现登录校验、权限控制 |
| 🔄 页面生命周期 | 自定义生命周期处理器,监听页面事件 |
| ✨ 自定义转场动画 | 支持页面级和全局转场动画配置 |
| 📦 单例页面 | 通过 singleton: true 实现页面复用 |
| 🪟 Dialog 页面 | 将页面以弹窗形式展示 |
| 📤 返回传参 | 支持页面返回时携带参数 |
二、快速上手:从零配置 HMRouter
2.1 安装依赖
首先安装 HMRouter 核心库:
bash
ohpm install @hadss/hmrouter
如果需要使用自定义转场动画,还需安装过渡动画库:
bash
ohpm install @hadss/hmrouter-transitions
2.2 配置编译插件
修改工程根目录的 hvigor/hvigor-config.json,添加路由编译插件依赖 :
json
{
"dependencies": {
"@hadss/hmrouter-plugin": "^1.0.0-rc.10"
}
}
然后在使用 HMRouter 的模块(entry/har/hsp)的 hvigorfile.ts 中引入插件:
entry 模块(Hap):
typescript
// 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 中初始化 HMRouterMgr :
typescript
// 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 AttributeUpdater<NavigationAttribute> {
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 跳转传参
发送方 :
typescript
HMRouterMgr.push({
pageUrl: 'ProductDetail',
param: {
productId: '12345',
title: '华为Mate 60'
}
});
接收方:
typescript
@HMRouter({ 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 回调,接收返回页面的数据 :
typescript
HMRouterMgr.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 模块跳转:
typescript
HMRouterMgr.push({ pageUrl: 'CartDetail' });
四、路由拦截器:登录校验与权限控制
拦截器是 HMRouter 最强大的功能之一,可在跳转前执行业务逻辑,常用于登录校验、权限验证、埋点统计等场景 。
4.1 定义拦截器
实现 IHMInterceptor 接口,使用 @HMInterceptor 注解 :
typescript
import { HMInterceptor, IHMInterceptor, HMInterceptorAction, HMInterceptorInfo } from '@hadss/hmrouter';
@HMInterceptor({ interceptorName: 'LoginCheckInterceptor' })
export class LoginCheckInterceptor implements IHMInterceptor {
handle(info: HMInterceptorInfo): HMInterceptorAction {
// 检查登录状态
const isLogin = AppStorage.get<boolean>('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 使用拦截器
局部拦截器(仅对指定页面生效):
typescript
@HMRouter({
pageUrl: 'ShoppingCart',
interceptors: ['LoginCheckInterceptor'] // 数组形式,支持多个
})
@Component
export struct ShoppingCart {
// ...
}
全局拦截器(对所有跳转生效):
typescript
@HMInterceptor({
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 定义生命周期
typescript
import { 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 绑定生命周期
typescript
@HMRouter({
pageUrl: 'HomePage',
lifecycle: 'PageLifecycle' // 关联生命周期处理器
})
@Component
export struct HomePage {
// ...
}
5.3 典型场景:两次返回退出应用
typescript
@HMLifecycle({ 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 注解定义动画类 :
typescript
import { 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 中指定动画 :
typescript
@HMRouter({
pageUrl: 'DetailPage',
animator: 'SlideUpAnimator' // 使用自定义动画
})
@Component
export struct DetailPage {
// ...
}
6.3 全局默认动画
在 HMNavigation 的 options 中配置全局动画 :
typescript
HMNavigation({
navigationId: 'mainNavigation',
options: {
standardAnimator: HMDefaultGlobalAnimator.STANDARD_ANIMATOR,
dialogAnimator: HMDefaultGlobalAnimator.DIALOG_ANIMATOR,
// ...
}
})
七、高级特性
7.1 单例页面
当页面初始化开销较大且需要频繁复用时(如视频播放页),可配置为单例模式 :
typescript
@HMRouter({
pageUrl: 'LivePlayer',
singleton: true // 页面栈中只有一个实例
})
@Component
export struct LivePlayer {
// ...
}
7.2 Dialog 页面
将页面以弹窗形式展示 :
typescript
@HMRouter({
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.json:
json
{
"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 。
Q:HAR 模块中的页面无法跳转?
A:确保 HAR 模块的 hvigorfile.ts 中配置了 harPlugin(),并在宿主模块的 oh-package.json5 中依赖该 HAR 。
Q:如何调试路由跳转?
A:可配合系统 NavPathStack 的 getAllPathName() 方法查看当前页面栈。
九、参考资源
HMRouter 通过注解驱动和插件化编译的方式,极大地简化了 HarmonyOS 应用的路由管理。无论是基础的页面跳转、跨模块通信,还是复杂的拦截器、生命周期管理,HMRouter 都能提供优雅的解决方案。建议在新项目中直接采用 HMRouter,可以显著提升路由相关的开发效率。
更多推荐



所有评论(0)