路由框架:实现页面解耦与拦截器的路由库(230)

📅 2026/7/21 18:24:06 👁️ 阅读次数 📝 编程学习
路由框架:实现页面解耦与拦截器的路由库(230)

在鸿蒙(HarmonyOS)原生开发中,随着应用规模的扩大,传统的硬编码路由会导致模块间高度耦合。为了实现页面解耦、统一拦截(如登录校验)以及跨模块通信,开发者通常会引入成熟的路由框架。

目前鸿蒙生态中最具代表性的路由方案是官方开源的HMRouter,以及社区广泛使用的ZRouterTheRouter

一、 官方开源方案:HMRouter

HMRouter 是鸿蒙官方推出的路由管理组件,旨在简化应用内原生页面的跳转逻辑。它底层封装了系统的NavigationNavDestinationNavPathStack,通过编译期注解处理器自动生成路由表,实现业务与路由的解耦。

  • 注解驱动与声明式路由:通过@HMRouter装饰器声明路由路径,支持字符串常量定义,并兼容 HAR/HSP/HAP 模块化方案。
  • 强大的拦截器机制:支持全局拦截、单页面拦截以及跳转时一次性拦截。开发者可以轻松实现未登录拦截、权限校验等逻辑。
  • 生命周期与转场动画:提供全局与单页面的生命周期回调,并内置了 slide、fade、scale 等转场动画,支持交互式动画配置。
  • 服务路由(Service Route):除了页面跳转,HMRouter 还支持通过@HMService注册服务,实现跨模块的方法调用与解耦。
5. 官方 HMRouter 初始化与页面声明实战 场景:在应用启动时初始化路由框架,并通过注解声明式定义页面路由,实现跨模块的无缝跳转。 typescript 编辑 // 1. 在 EntryAbility 中初始化路由框架 import { HMRouterMgr } from '@hadss/hmrouter'; export default class EntryAbility extends UIAbility { onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { HMRouterMgr.init({ context: this.context }); } } // 2. 使用注解声明页面路由(无需手动包裹 NavDestination) import { HMRouter, HMRouterMgr } from '@hadss/hmrouter'; @HMRouter({ pageUrl: 'page/detail' }) @Component export struct DetailPage { // 自动获取路由传递的参数 @State param: Object | null = HMRouterMgr.getCurrentParam(); build() { Column() { Text(`详情页参数: ${JSON.stringify(this.param)}`).fontSize(18); Button('返回并携带结果').onClick(() => { // 返回上一页并传递结果 HMRouterMgr.pop({ param: { status: 'success' } }); }); } .width('100%') .height('100%') .justifyContent(FlexAlign.Center); } } 6. 全局拦截器实战:未登录自动重定向 场景:在跳转到个人中心等受保护页面时,全局拦截器自动检查登录状态。若未登录,则拦截原始请求并重定向至登录页。 typescript 编辑 import { HMRouterMgr, HMInterceptorAction, HMInterceptorInfo } from '@hadss/hmrouter'; // 定义全局登录拦截器 export class LoginGlobalInterceptor { handle(info: HMInterceptorInfo): HMInterceptorAction { const isLogin = false; // 模拟未登录状态 if (!isLogin && info.targetName === 'page/profile') { // 拦截原始跳转,重定向至登录页,并携带目标页URL以便登录后返回 HMRouterMgr.push({ pageUrl: 'page/login', param: { targetUrl: info.targetName }, skipAllInterceptor: true // 登录页跳转跳过拦截器,防止死循环 }); return HMInterceptorAction.DO_REJECT; // 拒绝原始跳转 } return HMInterceptorAction.DO_NEXT; // 放行,继续执行下一个拦截器或跳转 } } 7. 跨模块服务路由:接口与实现解耦 场景:基础模块需要调用业务模块的方法(如获取用户信息),但不允许基础模块直接依赖业务模块。通过 @HMService 实现服务注册与发现。 typescript 编辑 // 1. 在业务模块中注册服务 import { HMService } from '@hadss/hmrouter'; export class UserService { @HMService({ serviceName: 'IUserService', singleton: true }) getUserInfo(): string { return '当前用户: HarmonyOS Dev'; } } // 2. 在基础模块中获取服务并调用(无需 import 实现类) // 通过 HMRouterMgr 获取服务实例 const userService = HMRouterMgr.getService('IUserService') as UserService; console.info(userService.getUserInfo());

二、 社区进阶方案:ZRouter 与 TheRouter

  • ZRouter:同样基于自定义注解和代码生成实现。它提供了极其优雅的链式调用 API(如ZRouter.getInstance().push("Login")),其全局拦截器(GlobalNavigateInterceptor)支持在onNavigate中根据页面的needLogin属性进行重定向和参数替换。
  • TheRouter:针对超大型项目的模块化协作,TheRouter 通过动态路由表和ServiceProvider机制,完美解决了复杂的跨模块依赖注入与服务发现痛点。
import { TheRouter, Route, Autowired } from '@therouter/library'; // 1. 声明路由并自动注入参数 @Route({ path: 'http://therouter.com/home' }) @Component export struct HomePage { @Autowired() userId: string = ''; aboutToAppear(): void { // 使用注解接收对象时,必须调用 inject TheRouter.inject(this); } build() { Column() { Text(`当前用户ID: ${this.userId}`).fontSize(18); } } } // 2. 发起跳转并传递参数 TheRouter .build('http://therouter.com/home') .withString('userId', 'U12345') .navigation();

三、 核心能力:路由拦截器(Interceptor)

拦截器是路由框架的核心价值之一。无论是 HMRouter 还是 ZRouter,都允许开发者在页面跳转前进行逻辑干预。

  • 全局鉴权:在跳转目标页面前,检查全局登录状态。若未登录,则中断原始跳转,重定向至登录页,并在登录成功后携带原参数继续跳转。
  • 埋点与日志:在全局拦截器中统一记录用户的页面访问轨迹(如srcName jump to targetName),无需在每个业务页面手动埋点。
import { HMInterceptor, HMInterceptorAction, IHMInterceptor, IHMInterceptorChain, HMRouterMgr } from '@hadss/hmrouter'; @HMInterceptor({ interceptorName: 'LoginCheckInterceptor' }) export class LoginCheckInterceptor implements IHMInterceptor { async intercept(chain: IHMInterceptorChain): Promise<void> { const info = chain.getRouterInfo(); const isLogin = false; // 模拟未登录状态 if (!isLogin && info.targetName === 'page/profile') { // 拦截原始跳转,重定向至登录页 info.context.getPromptAction().showToast({ message: '请先登录' }); HMRouterMgr.push({ pageUrl: 'page/login', param: { targetUrl: info.targetName }, skipAllInterceptor: true // 登录页跳转跳过拦截器,防止死循环 }); await chain.onIntercept(); // 拦截原始请求 } else { await chain.onContinue(); // 放行,继续执行跳转 } } }

四、 宿主容器与路由栈管理

  1. 路由表与名称一致性:使用pushPathByName时,传入的名称必须与配置文件(如route_map.json或注解中的pageUrl)完全一致,否则会导致跳转白屏或失败。
  2. 参数类型安全:跨页面传递复杂对象时,建议统一定义 Interface(如DetailParam)并导出,避免在多个页面中“随手拼对象”导致字段缺失或类型错误。
  3. 编译插件版本对齐:使用 HMRouter 等基于代码生成的框架时,必须确保编译插件(如@hadss/hmrouter-plugin)与核心库的版本严格一致,否则会导致编译失败或路由表生成异常。
  4. 宿主容器不可缺失:HMRouter 依赖系统的 Navigation 能力,必须在根页面(通常是@Entry组件)中包裹HMNavigationNavigation(ZRouter.getNavStack())容器,否则 push 操作会因找不到“宿主栈”而失效。
import { HMNavigation, HMDefaultGlobalAnimator } from '@hadss/hmrouter'; // 在根页面(@Entry)中必须包裹 HMNavigation 容器 @Entry @Component struct Index { build() { Column() { HMNavigation({ navigationId: 'mainNavigation', homePageUrl: 'page/home', // 首页路由地址 options: { standardAnimator: HMDefaultGlobalAnimator.STANDARD_ANIMATOR } }) } .width('100%') .height('100%'); } }

五、HMRouter 初始化与页面声明实战

场景:在应用启动时初始化路由框架,并通过注解声明式定义页面路由,实现跨模块的无缝跳转。

// 1. 在 EntryAbility 中初始化路由框架 import { HMRouterMgr } from '@hadss/hmrouter'; export default class EntryAbility extends UIAbility { onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { HMRouterMgr.init({ context: this.context }); } } // 2. 使用注解声明页面路由(无需手动包裹 NavDestination) import { HMRouter, HMRouterMgr } from '@hadss/hmrouter'; @HMRouter({ pageUrl: 'page/detail' }) @Component export struct DetailPage { // 自动获取路由传递的参数 @State param: Object | null = HMRouterMgr.getCurrentParam(); build() { Column() { Text(`详情页参数: ${JSON.stringify(this.param)}`).fontSize(18); Button('返回并携带结果').onClick(() => { // 返回上一页并传递结果 HMRouterMgr.pop({ param: { status: 'success' } }); }); } .width('100%') .height('100%') .justifyContent(FlexAlign.Center); } }

六、 全局拦截器实战:未登录自动重定向

场景:在跳转到个人中心等受保护页面时,全局拦截器自动检查登录状态。若未登录,则拦截原始请求并重定向至登录页。

import { HMRouterMgr, HMInterceptorAction, HMInterceptorInfo } from '@hadss/hmrouter'; // 定义全局登录拦截器 export class LoginGlobalInterceptor { handle(info: HMInterceptorInfo): HMInterceptorAction { const isLogin = false; // 模拟未登录状态 if (!isLogin && info.targetName === 'page/profile') { // 拦截原始跳转,重定向至登录页,并携带目标页URL以便登录后返回 HMRouterMgr.push({ pageUrl: 'page/login', param: { targetUrl: info.targetName }, skipAllInterceptor: true // 登录页跳转跳过拦截器,防止死循环 }); return HMInterceptorAction.DO_REJECT; // 拒绝原始跳转 } return HMInterceptorAction.DO_NEXT; // 放行,继续执行下一个拦截器或跳转 } }

七、跨模块服务路由:接口与实现解耦

场景:基础模块需要调用业务模块的方法(如获取用户信息),但不允许基础模块直接依赖业务模块。通过@HMService实现服务注册与发现。

// 1. 在业务模块中注册服务 import { HMService } from '@hadss/hmrouter'; export class UserService { @HMService({ serviceName: 'IUserService', singleton: true }) getUserInfo(): string { return '当前用户: HarmonyOS Dev'; } } // 2. 在基础模块中获取服务并调用(无需 import 实现类) // 通过 HMRouterMgr 获取服务实例 const userService = HMRouterMgr.getService('IUserService') as UserService; console.info(userService.getUserInfo());