[HarmonyOS] 解决HMRouter路由地址无法抽取的问题

解决HMRouter路由地址无法抽取的问题

背景

最近开始学习HarmonyOS开发,搭建项目的时候采用了 HMRouter 路由框架,在项目里使用到路由跳转,官方链接在这:

https://gitee.com/hadss/hmrouter/blob/master/HMRouterLibrary/README.md

但是发现一个比较严重的问题,就是路由地址无法抽取到一起进行管理,目前只能在当前的页面文件中写死路由地址,这样在项目里如果路由地址有修改,就需要在每一个页面文件里都进行修改,非常不方便。

上述表述可以用一个鲜明的例子来举证一下:

比如我们的项目结构如下:

harmony_os(项目名)|-entry|-features(业务组件模块路径)|-home(首页模块)|-mine(我的模块)|-...(其他业务模块)|-commons(公共组件模块路径)|-lib_net(网络组件)|-router_scheme(路由地址管理组件)|-...(其他公共组件)

大致如上的结构,我们希望的目标是,能够 在 router_scheme 模块里定义了所有路由地址常量,然后对于需要注册路由的 module,都来依赖这个 router_scheme 模块,这样在 router_scheme 模块里定义的路由地址常量,就能被其他 module 引用,从而避免在每一个页面文件里都写死路由地址,方便维护。

比如 将所有的 路由地址定义的常量存放到一个类或者N个类中(可以根据不同的业务module来拆分不同的类文件存放)

export class RouterConstants {public static readonly router_name_1: string = "router_name_1_value"public static readonly router_name_2: string = "router_name_2_value"public static readonly router_name_3: string = "router_name_3_value"public static readonly DemoNetPage: string = "routerscheme://entry/DemoNetPage"public static readonly DialogPage: string = "routerscheme://entry/DialogPage"public static readonly ProgramPage: string = "routerscheme://entry/ProgramPage"
}

如下图所示,红色的是路由 module,用来存放所有的路由常量类;绿色的是需要依赖路由常量类的 module,比如 feature1entry 模块,只需要依赖 router_scheme 模块,然后就可以直接引用 router_scheme 模块里定义的路由常量了。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

但是。。。。。理想很丰满,现实很骨感啊。。。。。。。。。官方gitee 上好多 issue都提出,如果将常量抽取到单独的 har 中,会识别不到。。。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

备用链接

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

但是本着 办法总比困难多 的想法,还是想到了一个折中的实现方案。。。

实现方案

我们的初始目标是希望能够将所有的路由地址常量存放到一个类或者N个类中,然后对于需要注册路由的 module,都来依赖这个 router_scheme 模块,这样在 router_scheme 模块里定义的路由地址常量,就能被其他 module 引用,从而避免在每一个页面文件里都写死路由地址,方便维护。

那么现在既然官方不支持,或者说是还没支持,那我们就要想个办法,先将所有的路由常量集中到一个类中去,这样万一后续他们支持了,迁移也很方便了~~~

如下简述实现方案,技术有限,仅供参考哈~~~

主要分这么几个步骤:

- 1.实现插件,通过插件将常量类写入到每一个需要支持路由的module中,并且统一命名
- 2.添加路由键值对映射配置表(其实就是你所有的路由名字与路由地址的映射表),便于第一步的插件识别用来生成路由类
- 3.执行插件
- 4.代码引用

1.实现 HarmonyOS plugin

通过官方文档,查找到编写插件的逻辑,实现该插件,插件的主要目的是将路由映射表插入到每一个需要支持路由的 module 中,并且统一命名,方便插件识别。

将如下的 plugin 代码,命名为 RouterNamesGeneratePlugin.ts,放在 config 文件夹下,然后在项目的根路径的 hvigorfile.ts 中引入,如下所示:

这样后续只要执行 sync 就会执行下述插件代码

源码如下:

import { FileUtil, hvigor, getNode, HvigorNode, HvigorTask, HvigorPlugin } from '@ohos/hvigor';// 实现自定义插件,sync的时候自动生成路由类
export function RouterNamesGeneratePlugin(): HvigorPlugin {// 路由表JSON文件地址let namesFilePath = "config/router_names.json5"// 路由生成规则配置文件地址let configFilePath = "config/router_config.json5"// 路由类文件名称let fileName = "RouterConstants"return {pluginId: 'RouterNamesGenerate',apply(node: HvigorNode) {// 路由数据源let routerNames = FileUtil.readJson5(namesFilePath)let routerList = routerNames['rent'] // 路由对象列表if (!routerList) {console.log(`debug_hvigorfile: routerList is null`)return}// 路由配置表let routerConfig = FileUtil.readJson5(configFilePath)let moduleNames = routerConfig['moduleNames'] // 路由对象列表if (!moduleNames) {console.log(`debug_hvigorfile: moduleNames 配置的module为空,不生成路由类 `)return}console.log(`debug_hvigorfile: 路由配置表 ↓↓↓↓↓↓↓↓↓↓↓↓`)moduleNames.forEach(element => {console.log(`debug_hvigorfile: moduleName=${element}`)})console.log(`debug_hvigorfile: 路由配置表 ↑↑↑↑↑↑↑↑↑↑↑↑`)console.log(`debug_hvigorfile: 路由表原始数据 ↓↓↓↓↓↓↓↓↓↓↓↓`)routerList.forEach(element => {console.log(`debug_hvigorfile: key=${element["key"]}, value=${element["value"]}`)})console.log(`debug_hvigorfile: 路由表原始数据 ↑↑↑↑↑↑↑↑↑↑↑↑`)// 获取所有节点const allNodes = hvigor.getAllNodes();for (let i = 0; i < allNodes.length; i++) {let nodeName = allNodes[i].getNodeName()let nodeDir = allNodes[i].getNodeDir()let getPath = nodeDir.getPath()// console.log(`debug_hvigorfile: module: nodeName=${nodeName}, getPath=${getPath}`)if (moduleNames.includes(nodeName)) {// console.log(`debug_hvigorfile: module: nodeName=${nodeName}, getPath=${getPath}  可以写入`)let newFilePath = getPath + `/src/main/ets/${fileName}.ets`// 判断是否存在FileUtil.ensureFileSync(newFilePath)let exist2 = FileUtil.exist(newFilePath)// console.log(`debug_hvigorfile: exist2: ${exist2}`)let date = new Date()let formatDate = date.toLocaleString()let tips = `// 自动生成,请勿修改 \n// 生成时间:${formatDate}`let a = `${tips} \nexport class ${fileName} {\n\t`let length = routerList.lengthfor (let j = 0; j < length; j++) {let element = routerList[j]// console.log(`debug_hvigorfile: 开始写入文件>>>>> key=${element["key"]}, value=${element["value"]}`)let key = element["key"]let value = element["value"]let prefix = (j == length - 1) ? "\n" : "\n\t"a += `public static readonly ${key}: string = "${value}"${prefix}`}a += `}`// 备注:这个 写入文件,不要使用异步写入,异步写入的话会存在先执行 HMRouter 的插件的case,就容易出问题了,需要保证在执行 HMRouter 插件之前,生成完所有的路由映射类FileUtil.writeFileSync(newFilePath, a)console.log(`debug_hvigorfile: moduleName[${nodeName}]: 写入完成`)}}// FileUtil.readFile('entry/test.txt').then(function(data) {//   console.log('readFile: ' + data);// });}}
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


export default {system: appTasks,plugins: [RouterNamesGeneratePlugin()]
}// 注册Task, 用于在添加路由之后,执行此任务来重新生成路由类
// 执行: hvigorw generateRouterNames  即可重新生成新的路由类
node.registerTask({name: 'generateRouterNames',run() {// 自动执行 RouterNamesGeneratePlugin}
});

2.添加配置信息

在项目的根路径下,新建 config 目录,将上述的 RouterNamesGeneratePlugin.ts 文件放进去,然后新建下述两个 json5 文件

  • 1.router_names.json5:用于存放所有的路由映射关系,json5的格式存储,键值对存储便于记录
  • 2.router_config.json5:用于配置那些 module 需要生成路由类,格式具体参考下方

举例:

router_names.json5 文件的内容规范如下:

  • rent: 便于后续区分不同的业务线,目前只设置这一个也行
  • key: 路由的名字,也就是最终在Page文件中的路由名称
  • value: 路由的具体地址
{"rent": [{"key": "DemoNetPage","value": "routerscheme://entry/DemoNetPage"},{"key": "DialogPage","value": "routerscheme://entry/DialogPage"},{"key": "ProgramPage","value": "routerscheme://entry/ProgramPage"}]
}

router_config.json5 文件的内容规范如下:

  • moduleNames: 用于配置需要生成路由类的module名字,需要在这配置一下

比如我的例子中,是要在 feature1entry 两个 module 中生成路由类,那么就将这俩module的名字配置一下。。。

{// 配置:需要生成路由类的module名字,需要在这配置一下"moduleNames": ["entry","feature1"]
}

3.执行插件

上述第一、第二步完成之后,就可以执行插件了,执行命令如下:
在项目根路径中的命令行中执行: hvigorw generateRouterNames 即可重新生成新的路由类;或者后续每次添加新的路由映射,也可以用它来执行重新生成路由映射类。

或者直接在项目根路径的 hvigorfile.ts 中随便回车一下,触发 sync 也可以执行构建。

hvigorw generateRouterNames

插件执行完毕后,会在 entryfeature1 两个 module 中生成 RouterConstants.ets 文件,如下图所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4.代码引用

完成上述三步之后,那么在模块中就可以直接引用了,比如 我定义了 router_name_3 这个路由,那么在模块中就可以这样引用了:

import { RouterConstants } from “…/RouterConstants”;
@HMRouter({ pageUrl: RouterConstants.router_name_3 })

就这么简单~~~~~~

import { HMRouter } from "@hadss/hmrouter";
import { RouterConstants } from "../RouterConstants";@HMRouter({ pageUrl: RouterConstants.router_name_3 })@Entry
@Component
export struct MainPage {@State message: string = 'Hello feature1_MainPage: ' + RouterConstants.router_name_3;build() {Row() {Column() {Text(this.message).fontSize(10).fontWeight(FontWeight.Bold)}.width('100%')}.height('100%')}
}

至此,完结有需要的小伙伴拿走不谢~
更加希望 HMRouter 后续能够支持常量抽取~~~

感谢~~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/62173.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

高级java每日一道面试题-2024年11月27日-JVM篇-JVM的永久代中会发生垃圾回收么?

如果有遗漏,评论区告诉我进行补充 面试官: JVM的永久代中会发生垃圾回收么? 我回答: 在Java虚拟机&#xff08;JVM&#xff09;的历史版本中&#xff0c;确实存在一个称为“永久代”&#xff08;Permanent Generation, 或者简称PermGen&#xff09;的内存区域。永久代主要用…

转录组数据挖掘(生物技能树)(第11节)下游分析

转录组数据挖掘&#xff08;生物技能树&#xff09;&#xff08;第11节&#xff09; 文章目录 R语言复习转录组数据差异分析差异分析的输入数据操作过程示例一&#xff1a;示例二&#xff1a;示例三&#xff1a;此代码只适用于人的样本 R语言复习 #### 读取 ####dat read.deli…

李宏毅机器学习课程知识点摘要(14-18集)

线性回归&#xff0c;逻辑回归&#xff08;线性回归sigmoid&#xff09;&#xff0c;神经网络 linear regression &#xff0c; logistic regression &#xff0c; neutral network 里面的偏导的相量有几百万维&#xff0c;这就是neutral network的不同&#xff0c;他是…

Labelme常用快捷键

Labelme是一款常用的图像标注工具&#xff0c;其快捷键可以提高标注效率。以下是一些常用的Labelme快捷键&#xff1a; 基本导航 A&#xff1a;切换到上一张图片。D&#xff1a;切换到下一张图片。 标注操作 Ctrl E&#xff1a;选中标注框或标签时按下可打开编辑窗口。Ctrl …

【接口封装】——7、连接并使用 MySQL 数据库

头文件&#xff1a; #include <qsqlquery.h> #include <qsqldatabase.h>&#xff08;注&#xff1a;需要先适配数据库&#xff09; 函数定义&#xff1a; public:bool verifyLogin(const QString& account, const QString& password);QString getUserName(…

深入理解Go语言中的`sync.Pool`与常规内存分配

在Go语言的并发编程中&#xff0c;内存管理是一个不可忽视的话题。sync.Pool作为Go标准库中的一个特殊工具&#xff0c;提供了一种对象池化机制&#xff0c;以优化内存分配和垃圾回收&#xff08;GC&#xff09;。本文将深入探讨sync.Pool与常规内存分配的主要区别&#xff0c;…

WonderJourney 学习笔记

目录 原理 所有场景的参数&#xff1a; 原理 Pytorch3D&#xff1a;用于高性能的3D渲染&#xff0c;确保生成的场景具有高度的真实感和细节。GPT-4&#xff1a;通过生成场景描述&#xff0c;为每一帧提供丰富的背景故事和情感。MiDaS&#xff1a;用于深度估计&#xff0c;确…

一个vue项目如何运行在docker

将 Vue.js 应用程序通过 Docker 发布是一个非常常见的做法&#xff0c;它可以帮助你轻松地部署应用到不同的环境中。下面是一个简单的指南&#xff0c;介绍如何为 Vue.js 项目创建 Dockerfile 并进行构建和运行。 第一步&#xff1a;安装 Docker 确保你的开发机器上已经安装了…

李永平:以科技创新为引擎,驱动中国国际未来产业研究院不断前行

作者:李望 在科技创新与产业升级的滚滚洪流中,唯有洞察未来者,方能引领时代浪潮。近日,中国国际未来产业研究院迎来了重量级嘉宾——李永平院士。他的加盟,为研究院注入了全新的活力。作为业界的领军人物,李永平院士将担任研究院常务副院长、资深专家及高级法律顾问,共同规划未…

运维面试题.云计算面试题

一、选择题(每题1分,合计15分) 1.若当前目录为 /home,命令 ls–l 将显示 home 目录下的( )。 A.所有文件 B.所有隐含文件 C.所有非隐含文件 D.文件的具体信息 2.如果要列出一个目录下的所有文件需要使用命令行( )。 A. ls–l B. ls C. ls–a(all) D. ls–d 3.下面关于文件…

11.27作业

C语言关键概念 ├── static │ ├── 局部变量 │ │ └── 生命周期持续整个程序运行 │ └── 全局变量和函数 │ └── 仅在定义文件中可见 ├── extern │ └── 引入其他文件中的全局变量 ├── typedef │ ├── 类型重命名 │ │ ├─…

生产环境中,nginx 最多可以代理多少台服务器,这个应该考虑哪些参数 ?怎么计算呢

生产环境中&#xff0c;nginx 最多可以代理多少台服务器&#xff0c;这个应该考虑哪些参数 &#xff1f;怎么计算呢 关键参数计算方法评估步骤总结 在生产环境中&#xff0c;Nginx最多可以代理的服务器数量并没有一个固定的限制&#xff0c;它取决于多个因素&#xff0c;包括Ng…

[DL]深度学习_扩散模型正弦时间编码

1 扩散模型时间步嵌入 1.1 时间步正弦编码 在扩散模型按时间步 t 进行加噪去噪过程时&#xff0c;需要包括反映噪声水平的时间步长 t 作为噪声预测器的额外输入。但是最初与图像配套的时间步 t 是数字&#xff0c;需要将代表时间步 t 的数字编码为向量嵌入。嵌入时间向量的宽…

Golang context 的作用和实现原理

context的作用 Go语言中的context包提供了一种在进程中跨API和跨进程边界传递取消信号、超时和其他请求范围的值的方式。context的主要作用包括&#xff1a; 取消信号&#xff08;Cancellation&#xff09;&#xff1a; 当一个操作需要取消时&#xff0c;可以通过context传递…

【超全】目标检测模型分类对比与综述:单阶段、双阶段、有无锚点、DETR、旋转框

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…

Llmcad: Fast and scalable on-device large language model inference

题目&#xff1a;Llmcad: Fast and scalable on-device large language model inference 发表于2023.09 链接&#xff1a;https://arxiv.org/pdf/2309.04255 声称是第一篇speculative decoding边缘设备的论文&#xff08;不一定是绝对的第一篇&#xff09;&#xff0c;不开源…

Edge浏览器保留数据,无损降级退回老版本+禁止更新教程(适用于Chrome)

3 个月前阿虚就已经写文章告警过大家&#xff0c;Chromium 内核的浏览器将在 127 以上版本开始限制仍在使用 Manifest V2 规范的扩展&#xff1a;https://mp.weixin.qq.com/s/v1gINxg5vMh86kdOOmqc6A 像是 IDM、油猴脚本管理器、uBblock 等扩展都会受到影响&#xff0c;后续将无…

人工智能零基础入门学习笔记

学习视频&#xff1a;人工智能零基础入门教程 文章目录 1.简介2.应用3.演进4.机器学习5.深度学习6.强化学习7.图像识别8.自然语言9.Python10.Python开发环境11.机器学习算法1.多元线性回归项自实战&#xff1a;糖尿病回归预测 2.逻辑回归3.Softmax回归项目实战&#xff1a;鸢尾…

Spring Boot 3 集成 Spring Security(3)数据管理

文章目录 准备工作新建项目引入MyBatis-Plus依赖创建表结构生成基础代码 逻辑实现application.yml配置SecurityConfig 配置自定义 UserDetailsService创建测试 启动测试 在前面的文章中我们介绍了 《Spring Boot 3 集成 Spring Security&#xff08;1&#xff09;认证》和 《…

Wireshark抓取HTTPS流量技巧

一、工具准备 首先安装wireshark工具&#xff0c;官方链接&#xff1a;Wireshark Go Deep 二、环境变量配置 TLS 加密的核心是会话密钥。这些密钥由客户端和服务器协商生成&#xff0c;用于对通信流量进行对称加密。如果能通过 SSL/TLS 日志文件&#xff08;例如包含密钥的…