# AppRouterProject **Repository Path**: zhongrui_developer/AppRouterProject ## Basic Information - **Project Name**: AppRouterProject - **Description**: 鸿蒙动态路由开源库。 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 39 - **Forks**: 9 - **Created**: 2024-05-31 - **Last Updated**: 2025-07-15 ## Categories & Tags **Categories**: Uncategorized **Tags**: harmony, HarmonyOS组件 ## README ![输入图片说明](D1389CBB-4FFB-44a4-A6B1-3A0B6A2B5DF1.png) # AppRouter ## 简介 AppRouter通过Navigation+hvigor插件实现的动态路由方案,便于项目各模块之间的页面跳转 ## 下载安装 ```text ohpm install @zhongrui/app_router ``` ### 或者[下载har](https://gitee.com/zhongrui_developer/AppRouterProject/raw/dev/lib/AppRouter.har)
#### 该路由方案实现的效果: entry模块依赖A模块(Har)、B模块(Har)、C模块(Hsp),ABC三个模块互相不依赖,可实现这4个模块之间互相进行页面跳转(达到解耦的效果) 比如: 1. entry模块页面跳转至->entry模块、A模块、B模块、C模块页面 A模块页面跳转至->entry模块、A模块、B模块、C模块页面 . . . 2. 提供拦截器,在跳转某个页面时,可以根据业务需求在页面跳转前拦截(如果跳转某个不存在的组件,拦截器不会触发,避免处理无效逻辑) 3. 根据注解参数可配置跳转目标页面前是否需要验证登录状态,在未登录的情况下,跳转目标页面前会执行登录操作 4. 根据注解参数可配置在步骤3执行登录操作之后,是否继续执行登录前的页面跳转动作 5. App启动时可以配置不用加载所有模块的路由表数据(相对启动时加载所有路由表数据,不加载可以避免增加启动耗时问题),在页面跳转时会动态加载,然后加入缓存中,下次跳转直接读缓存 ## 首先展示跳转逻辑与目标页面定义方式 1. 这是封装之后具体使用时Navigation根视图和页面跳转代码 ```typescript @Entry @Component struct Index { @Builder getBuilder(path: string) { //此处写法固定,不会随着组件数量增加而增加额外逻辑 AppRouter.getBuilderByPath(path)?.builder(path as Object) } build() { //Navigation这里记得传入AppRouter.getRootStack(),否则跳转不生效 Navigation(AppRouter.getRootStack()) { Button("跳转目标页面").onClick(() => { //1:通过路由跳转目标页面 AppRouter.push("entry/target") }) }.hideTitleBar(true) .navDestination(this.getBuilder) } } ``` 2. 定义目标页面的代码(不用@Entry修饰,不用在main_pages.json文件里配置组件路径) **重点注意:1:组件需要export 2:组件名需要和文件名保持一致** ```typescript import { RouterPath } from '@zhongrui/app_router/Index'; //此处path只能用字面量,不能用变量或者外部类定义的常量 @RouterPath({ path: "entry/target"}) @Component export struct Target { build() { NavDestination() { Text("目标页面") }.hideTitleBar(true) .onAppear(()=>{ //组件挂载时触发 }) .onDisAppear(()=>{ //组件卸载时触发 }) .onShown(()=>{ //页面显示时触发,相当于@Entry修饰的组件onPageShow() }) .onHidden(()=>{ //页面隐藏时触发,相当于@Entry修饰的组件onPageHide() }) .onBackPressed(()=>{ //如果返回true,则会拦截返回键 return false }) } } ``` ## 配置教程 如果不想看详细说明,只想知道项目使用时的简单配置->[简单配置](https://gitee.com/zhongrui_developer/AppRouterProject/blob/master/README_simple.md) ### 1. 依赖app_router库 在每个模块的oh-package.json5配置 ```json { "dependencies": { //配置完记得点击右上角的Install Now "@zhongrui/app_router": "^1.0.4" } } ``` ### 2. 打开entry类型模块内的build-profile.json5文件 在节点buildOption->arkOptions->runtimeOnly->packages字段下添加所有被entry模块依赖且使用动态路由的模块名 ```json { "buildOption": { "arkOptions": { "runtimeOnly": { "packages": [ //按照实际情况添加entry模块依赖的所有模块名 "HarA", "HspB" ] } } } } ``` ### 3. 在项目工程hvigor目录中的hvigor-config.json5文件中配置 [**查看app_router_hvigor_plugin版本号**](https://gitee.com/zhongrui_developer/AppRouterProject/blob/master/hvigor_plugin/AppRouterPlugin/version_name.md) ```text { "dependencies": { //1:配置安装插件(配置完记得点击右上角的Install Now) "app_router_hvigor_plugin": "版本号" } } ``` 或者 [点击下载插件包](https://gitee.com/zhongrui_developer/AppRouterProject/raw/master/hvigor_plugin_lib/app_router_hvigor_plugin-1.0.8.tgz) ```text { "dependencies": { //1:配置安装插件(配置完记得点击右上角的Install Now) "app_router_hvigor_plugin": "file:../插件包目录", } } ``` ### 4. 配置各个模块的hvigorfile.ts文件(不是项目工程根目录下的hvigorfile.ts) 只需要复制两处代码,其他地方不要复制,防止出错 ```text //entry类型 import { hapTasks } from '@ohos/hvigor-ohos-plugin'; //非entry类型 import { harTasks } from '@ohos/hvigor-ohos-plugin'; //1:导入插件包和配置类(直接复制该行代码) import { AppRouterPlugin } from "app_router_hvigor_plugin" export default { system: hapTasks,//entry类型:hapTasks, 非entry类型:harTasks //2:注册插件AppRouterPlugin()(直接复制AppRouterPlugin方法块) plugins: [AppRouterPlugin({ //3:(重点注意)entry类型的模块传true,非entry类型传false "isEntry": true, "routerDependencyName":"@zhongrui/app_router", //扫描配置@RouterPath装饰器的组件所在的具体路径,可以加快编译速度,不配置scanPackagePath参数,默认路径为:"src/main/ets" "scanPackagePath": ["src/main/ets"] })] } ``` ##### 参数说明AppRouterPlugin() ```text { // 当前module是否是entry类型 isEntry: false, // 当前module需要扫描的包路径(建议配置使用@RouterPath装饰器的组件所在的具体路径,可以加快编译速度),不设置默认扫描模块下面所有文件目录 // 如果配置["src/main/ets/xxx/view", "src/main/ets/xxx/pages"],则会扫描该路径内的所有文件 scanPackagePath: [], // 当前module需要扫描的文件夹名称,比如["pages","page","view"],则会扫描模块src/main/ets内的所有pages,page,view目录以及子目录的文件 scanPackageName: [], // 当前module不需要扫描的路径或者文件 ignorePath: [], //以下全是默认配置,一般不用特意修改 // 路由注解名称 annotation: "RouterPath", // 是否开启调试模式,true:开启编译阶段输出日志 debug: false, // 当前module自动生成注册组件方法的文件路径 generatePath: "src/main/ets/_generated", // 当前module自动生成注册组件方法的文件名字 generateName: "AutoRouterBuilder.ets", // 当前module自动生成路由表的文件名字 generateMapName: "AutoRouterMap.ets", //被Entry模块依赖时设置的别名,例如:"@test/harA": "file:../HarA",此时需要设置entryDependencyName:"@test/harA" entryDependencyName?: string, //import { AppRouter } from '@zhongrui/app_router/Index', //依赖的路由模块名称 routerDependencyName: "@zhongrui/app_router", //路由名称 routerClassName: "AppRouter", } ``` ## 使用说明(配置完成后,记得build一下项目) ### 1.初始化 entry模块oh-package.json5文件依赖的module名称必须在初始化时传入 比如entry模块依赖了HarA,HarB,HspC三个模块, 那么AppRouter.init初始化的第一个参数就是:["HarA","B","@ohos/HspC"] 如果被依赖设置的别名和模块名不一致,比如:"B": "file:../HarB", 则需要在HarB模块的hvigorfile.ts文件AppRouterPlugin()中设置参数entryDependencyName:B ```json { "dependencies": { //别名和模块名一致 "HarA": "file:../HarA", //别名和模块名不一致 "B": "file:../HarB", //别名和模块名不一致 "@ohos/HspC": "file:../HspC" } } ``` ```typescript //固定写法,第一个参数记得根据项目依赖情况设置,其他参数直接复制即可 AppRouter.init(["HarA","B","@ohos/HspC"], { entryMapList: () => getEntryRouterMap(), entryBuilder: (group: string, name: string) => {BuildRegister(group, name)}, debug: false, isMultiPacket: true, initAllMap:false }) ``` ```text //参数说明 { //entry模块的路由表信息(因为entry类型的module无法动态import自己,模块内一般都是用的相对路径,所以需要主动处理路由表相关逻辑) entryMapList: () => getEntryRouterMap(), //entry模块注册WrappedBuilder逻辑,理由同上 entryBuilder: (group: string, name: string) => {BuildRegister(group, name)}, //是否打开调试模式 debug: false //启动app时是否初始化所有模块的路由map表数据,设置为false不会影响启动时间,页面跳转时会动态加载路由表 initAllMap: false //是否是多hap或者工程存在hsp模块,如果项目中存在其他Hap模块或者Hsp模块依赖动态路由库,则设置为true isMultiPacket: true } ``` ### 注解说明 @RouterPath({path:"xxx/xxx",des:"组件描述",needLogin:false,autoExecute:false}) 1. path参数:代表页面路径,通过路由进行跳转时AppRouter.push(path)传入的参数必须一致才能生效 格式为group/name组合,也可以不设置group,只设置name,比如 path:"home",如果项目页面很多,建议使用group/name格式 2. des:方便开发人员维护,增加的一个组件描述字段,没有实际作用 3. needLogin:跳转到该页面是否需要登录(默认为false),如果设置为true, 需要配合AppRouter.setLoginCheckListener()使用,下方有对该方法有说明 4. autoExecute:配合needLogin参数使用(默认为false),如果needLogin和autoExecute都设置为true,那么登录成功之后继续执行登录前的页面跳转逻辑 需要配合AppRouter.setLoginCheckListener()使用,下方有对该方法有说明 ### 2.api使用 ```typescript //是否存在路由页面 AppRouter.existBuilder(path).then((result) => { //result true:存在,false:不存在 }) //获取NavPathStack,在Navigation根视图设置 let navPathStack:NavPathStack=AppRouter.getRootStack() //页面跳转使用方式和官方api一致 //跳转目标页面 AppRouter.push("entry/main", param, true) //跳转目标页面并设置回传监听 AppRouter.pushForResult("entry/main", param, (result, prePagePath, prePageParam) => //上个页面退出时,使用popAndResult回传 result:回传的参数 prePagePath:上一个页面的path prePageParam:上一个页面获取的参数 }, true) //返回 AppRouter.pop(true) //返回并回传结果 AppRouter.popAndResult(param, true) //页面替换 AppRouter.replace("entry/main", param, true) //也可以获取跟视图的NavPathStack执行对应的方法 let navPathStack: NavPathStack = AppRouter.getRootStack() navPathStack...此处省略所有官方api //如果在Navigation视图内部又嵌套使用了Navigation,通过getStack()获取NavPathStack AppRouter.getStack("key") //添加拦截器 AppRouter.addInterceptor("key", (path, param, isContinue: () => void) => { //如果需要通过接口返回的数据来判断是否需要拦截,可以先返回true拦截掉,等接口响应之后,再调用isContinue() 继续执行之前的页面跳转操作 path:页面路径 param:跳转页面的参数 isContinue:是否继续执行拦截前的页面跳转逻辑 //返回true拦截页面跳转 return true }) //移除拦截器 AppRouter.removeInterceptor("key") //监听登录状态 AppRouter.setLoginCheckListener(() => { //true:已经登录状态,false:未登录 return true }) //通知登录操作 AppRouter.setLoginListener((result: (loginSuccess: boolean) => void) => { //执行登录操作后,通过result(true) 通知登录成功, result(true) }) ``` #### 参考资料 [动态路由Sample](https://gitee.com/harmonyos-cases/cases/tree/master/CommonAppDevelopment/common/routermodule) #### 开源协议 本项目基于 [MIT license](https://gitee.com/zhongrui_developer/AppRouterProject/blob/master/LICENSE) ,请自由地享受和参与开源。