一款功能强大的路由框架,聚焦应用内原生页面的跳转,帮助开发者更好的进行模块间解耦。底层对系统Navigation进行封装,提供了可复用的路由拦截、页面生命周期、自定义转场动画,并且在传参、额外的生命周期、服务型路由方面对系统能力进行了扩展。
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 9 个月前 | ||
| 1 年前 | ||
| 26 天前 | ||
| 28 天前 | ||
| 10 小时前 | ||
| 28 天前 | ||
| 10 小时前 | ||
| 2 个月前 | ||
| 3 个月前 | ||
| 10 小时前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 2 个月前 | ||
| 10 个月前 | ||
| 7 个月前 | ||
| 3 个月前 | ||
| 7 个月前 | ||
| 9 个月前 | ||
| 8 个月前 |
HMRouter
HMRouter作为应用内页面跳转场景解决方案,为开发者提供了功能完备、高效易用的路由框架。
HMRouter底层对系统Navigation进行封装,集成了Navigation、NavDestination、NavPathStack的系统能力,提供了可复用的路由拦截、页面生命周期、自定义转场动画,并且在跳转传参、额外的生命周期、服务型路由方面对系统能力进行了扩展,同时开发者可以高效的将历史代码中的Navigation组件接入到HMRouter框架中。
目的是让开发者在开发过程中减少模板代码,降低拦截器、自定义转场动画、组件感知页面生命周期等高频开发场景的实现复杂度,帮助开发者更好的实现路由与业务模块间的解耦。
特性
- 基于注解声明路由信息(普通页面、Dialog页面、单例页面)
- 注解参数支持使用字符串常量定义
- 页面路径支持正则匹配
- 支持在Har、Hsp、Hap中使用
- 支持Navigation路由栈嵌套
- 支持服务型路由
- 跳转时支持标准URL解析
- 支持路由拦截器(包含全局拦截、单页面拦截、跳转时一次性拦截)
- 支持生命周期回调(包含全局生命周期、单页面生命周期、NavBar生命周期)
- 内置转场动画(普通页面、Dialog),支持交互式转场动画,同时支持配置某个页面的转场动画、跳转时的一次性动画
- 提供更多高阶转场动画,包括一镜到底等(需依赖
@hadss/hmrouter-transitions) - 支持配置自定义页面模版,可以更灵活的生成页面文件
- 支持混淆白名单自动配置
- 支持与系统Navigation/NavDestination组件混用
依赖系统版本
- 编译工程要求的SDK版本: Ohos_sdk_public 6.0.0 (API 20 Release)及以上
- 应用运行要求的SDK版本: Ohos_sdk_public 5.0.0 (API 12 Release)及以上
快速开始
1. 安装依赖
使用 ohpm 安装
# 安装路由框架核心库
ohpm install @hadss/hmrouter
# 如需高级转场动画,安装转场动画库
ohpm install @hadss/hmrouter-transitions
2. 配置编译插件
依赖配置
插件版本建议和库的版本保持一致
修改工程根目录下的hvigor/hvigor-config.json 文件,加入路由编译插件
{
"dependencies": {
"@hadss/hmrouter-plugin": "latest" // 使用npm仓版本号
},
// ...其余配置
}
插件配置
修改工程根目录下的hvigorfile.ts,使用路由编译插件
// 工程根目录/hvigorfile.ts
import { appTasks } from '@ohos/hvigor-ohos-plugin';
import { appPlugin } from "@hadss/hmrouter-plugin";
export default {
system: appTasks,
plugins: [appPlugin({ ignoreModuleNames: [ /** 不需要扫描的模块 **/ ] })]
};
模块中单独配置,使用
modulePlugin()插件配置详情请参考插件使用说明
3. 初始化路由框架
在 UIAbility 或者启动框架 AppStartup 中初始化路由框架
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// 日志开启需在init之前调用,否则会丢失初始化日志
HMRouterMgr.openLog("INFO")
HMRouterMgr.init({
context: this.context
})
}
}
使用启动框架请查看:如何在启动框架中初始化HMRouter
4. 定义路由入口
HMRouter 依赖系统 Navigation 能力,所以必须在页面中定义一个 HMNavigation 容器,并设置相关参数,具体代码如下:
@Entry
@Component
export struct Index {
modifier: MyNavModifier = new MyNavModifier();
build() {
// @Entry中需要再套一层容器组件,Column或者Stack
Column(){
// 使用HMNavigation容器
HMNavigation({
navigationId: 'MainNavigation', homePageUrl: 'HomePage',
options: {
standardAnimator: HMDefaultGlobalAnimator.STANDARD_ANIMATOR,
dialogAnimator: HMDefaultGlobalAnimator.DIALOG_ANIMATOR,
modifier: this.modifier
}
})
}
.height('100%')
.width('100%')
}
}
class MyNavModifier extends AttributeUpdater<NavigationAttribute> {
initializeModifier(instance: NavigationAttribute): void {
instance.hideNavBar(true);
}
}
Navigation的系统属性通过modifier传递,部分modifier不支持的属性使用options设置
5. 页面定义与路由跳转
使用 @HMRouter 标签定义页面,绑定拦截器、生命周期及自定义转场动画
@HMRouter({
pageUrl: 'PageB',
interceptor: ['PageInterceptor'],
lifecycle: 'pageLifecycle',
animator: 'pageAnimator'
})
@Component
export struct PageB {
// 获取生命周期中定义的状态变量
@State model: ObservedModel | null = (HMRouterMgr.getCurrentLifecycleOwner().getLifecycle() as PageLifecycle).model
@State param: HMPageParam = HMRouterMgr.getCurrentParam(HMParamType.all)
build() {
Column() {
Text(`${this.model?.property}`)
Text(`${this.param.urlParam?.get('msg')}`)
}
}
}
定义页面 HomePage,使用 HMRouterMgr.push 执行路由跳转至 PageB
const PAGE_URL: string = 'HomePage'
@HMRouter({ pageUrl: PAGE_URL })
@Component
export struct HomePage {
build() {
Column() {
Button('Push')
.onClick(() => {
HMRouterMgr.push({ pageUrl: 'PageB?msg=abcdef' })
})
}
}
}
路由跳转支持URL带参数的方式,例如定义的页面pageUrl:
/pages1/users,跳转时可以指定pageUrl为:/pages1/users?msg=1234通过HMRouterMgr.getCurrentParam传入HMParamType.all获取URL的参数内容
6. 定义拦截器
使用 HMInterceptor 定义拦截器,并实现IHMInterceptor接口
@HMInterceptor({ interceptorName: 'PageInterceptor' })
export class PageInterceptor implements IHMInterceptor {
handle(info: HMInterceptorInfo): HMInterceptorAction {
if (isLogin) {
// 跳转下一个拦截器处理
return HMInterceptorAction.DO_NEXT;
} else {
HMRouterMgr.push({
pageUrl: 'LoginPage',
param: { targetUrl: info.targetName },
skipAllInterceptor: true
})
// 拦截结束,不再执行下一个拦截器,不再执行相关转场和路由栈操作
return HMInterceptorAction.DO_REJECT;
}
}
}
7. 定义生命周期
组件感知页面生命周期
通过 addObserver 接口,组件可以感知页面的生命周期事件:
@Component
struct ChildComponent {
@State backPressCount: number = 0;
private lifecycleOwner = HMRouterMgr.getCurrentLifecycleOwner();
private handleCallback = () => {
this.showToast();
this.backPressCount++;
return true;
}
aboutToAppear(): void {
this.lifecycleOwner?.addObserver(HMLifecycleState.onBackPressed, this.handleCallback);
}
aboutToDisappear(): void {
this.lifecycleOwner?.removeObserver(HMLifecycleState.onBackPressed, this.handleCallback);
}
// 组件内定义的方法
showToast() {
this.getUIContext().getPromptAction().showToast({ message: RouterPageConstant.LIFECYCLE_CASE1_TOAST });
}
build() {
// UI内容
}
}
页面绑定生命周期
使用@HMLifecycle标签定义生命周期处理器,并实现IHMLifecycle接口,页面可在 @HMRouter 注解中通过 lifecycle 属性来绑定
@HMLifecycle({ lifecycleName: 'PageLifecycle' })
export class PageLifecycle implements IHMLifecycle {
model: ObservedModel = new ObservedModel()
private time: number = 0;
onShown(ctx: HMLifecycleContext): void {
this.time = new Date().getTime();
}
onHidden(ctx: HMLifecycleContext): void {
const duration = new Date().getTime() - this.time;
console.info(`Page ${ctx.navContext?.pathInfo.name} stay ${duration}`);
}
}
8. 定义转场动画
通过@HMAnimator标签定义转场动画,并实现IHMAnimator接口
@HMAnimator({ animatorName: 'PageAnimator' })
export class PageAnimator implements IHMAnimator {
effect(enterHandle: HMAnimatorHandle, exitHandle: HMAnimatorHandle): void {
// 入场动画
enterHandle.start((modifier: AttributeUpdater<NavDestinationAttribute>) => {
modifier.attribute?.translate({ y: "100%" }).opacity(0.4);
}).finish((modifier: AttributeUpdater<NavDestinationAttribute>) => {
modifier.attribute?.translate({ y: "0" }).opacity(1);
}).onFinish((modifier: AttributeUpdater<NavDestinationAttribute>) => {
modifier.attribute?.translate({ y: "0" }).opacity(1);
});
// 出场动画
exitHandle.start((modifier: AttributeUpdater<NavDestinationAttribute>) => {
modifier.attribute?.translate({ y: "0" }).opacity(1);
}).finish((modifier: AttributeUpdater<NavDestinationAttribute>) => {
modifier.attribute?.translate({ y: "100%" }).opacity(0.4);
}).onFinish((modifier: AttributeUpdater<NavDestinationAttribute>) => {
modifier.attribute?.translate({ y: "0" }).opacity(1);
});
}
}
自定义转场动画的详细使用:查看详情
9. 服务路由使用
服务路由用于类似服务提供发现机制(Service Provider Interface),通过不依赖实现模块的方式获取接口实例并调用方法,可以直接获取服务实例对象,也可以直接进行方法级服务调用
// 方法级服务
export class CustomService {
@HMService({ serviceName: 'testFunWithReturn' })
testFunWithReturn(param1: string, param2: string): string {
return `调用服务 testFunWithReturn:${param1} ${param2}`
}
}
// 定义服务接口
interface IDataService {
fetchData(page: number, size: number): Promise<Object[]>;
}
// 实现服务提供者
@HMServiceProvider({ serviceName: 'DataService', singleton: true })
export class DataServiceImpl implements IDataService {
async fetchData(page: number, size: number): Promise<Object[]> {
// 实现数据获取逻辑
return [];
}
}
@HMRouter({ pageUrl: 'test://MainPage' })
@Component
export struct Index {
build() {
Row() {
Column({ space: 8 }) {
Button('service').onClick(() => {
// 使用getService拿到实例对象
let data = HMRouterMgr.getService<IDataService>('DataService').fetchData();
// 直接调用方法级服务
Logger.info(HMRouterMgr.request('testFunWithReturn', 'home', 'service').data)
})
}
.width('100%')
}
.height('100%')
}
}
应用内页面跳转场景解决方案
与系统Navigation/NavDestination组件混用说明
混淆说明
API参考
插件使用说明
兼容性矩阵
| HMRouter运行库 查看日志 |
映射 | HMRouter动效库 查看日志 |
映射 | HMRouter插件 查看日志 |
|---|---|---|---|---|
| 1.2.4(推荐版本) | → | 1.2.4(推荐版本) | → | 1.2.4(推荐版本) |
| 1.2.3 | → | 1.2.3 | → | 1.2.3 |
| 1.2.3-rc.1 | → | 1.2.3-rc.1 | → | 1.2.3-rc.1 |
| 1.2.3-rc.0 | → | 1.2.3-rc.0 | → | 1.2.3-rc.0 |
| 1.2.2 | → | 1.2.2 | → | 1.2.2 |
| 1.2.0 | → | 1.2.0 | → | 1.2.0 |
| 1.2.0-rc.0 | → | 1.2.0-rc.0 | → | 1.2.0-rc.0 |
| 1.2.0-beta.1 | → | 1.2.0-beta.1 | → | 1.2.0-beta.1 |
| 1.2.0-beta.0 | → | 1.2.0-beta.0 | → | 1.2.0-beta.0 |
| 1.0.0-rc.10 | → | 1.0.0-rc.10 | → | 1.0.0-rc.9 |
FAQ
Wiki
Sample参考
-
Sample示例代码,通过购物App展示
HMRouter在页面跳转场景中的使用 -
更丰富、更完整的API示例代码查看详情
原理介绍
贡献代码
使用过程中发现任何问题都可以提 Issue ,当然,也非常欢迎发 PullRequest 共建。
开源协议
本项目基于 Apache License 2.0 ,请自由地享受和参与开源。
项目介绍
一款功能强大的路由框架,聚焦应用内原生页面的跳转,帮助开发者更好的进行模块间解耦。底层对系统Navigation进行封装,提供了可复用的路由拦截、页面生命周期、自定义转场动画,并且在传参、额外的生命周期、服务型路由方面对系统能力进行了扩展。
定制我的领域