[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.length
          for (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 后续能够支持常量抽取~~~

感谢~~~

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ElasticSearch学习了解笔记

搜索引擎的原理&#xff1a; 1、查询分析&#xff08;自然语言处理&#xff09;理解用户需求 2、分词技术 3、关键词搜索匹配 4、搜索排序 lucence Lucene 是一个成熟的权威检索库 Elasticsearch 的搜索原理简单过程是&#xff0c;索引系统通过扫描文章中的每一个词&#xff…

ffmpeg视频滤镜:提取缩略图-framestep

滤镜描述 官网地址 > FFmpeg Filters Documentation 这个滤镜会间隔N帧抽取一帧图片&#xff0c;因此这个可以用于设置视频的缩略图。总体上这个滤镜比较简单。 滤镜使用 滤镜参数 framestep AVOptions:step <int> ..FV....... set frame st…

【C++11】可变参数模板/新的类功能/lambda/包装器--C++

文章目录 一、可变参数模板1、基本语法及原理2、包扩展3、empalce系列接口 二、新的类功能1、默认的移动构造和移动赋值2、成员变量声明时给缺省值3、defult和delete4、final与override 三、STL中一些变化四、lambda1、lambda表达式语法2、捕捉列表3、lambda的应用4、lambda的原…

云网络基础- TCP/IP 协议

文章目录 典型服务模式TCP/IP 协议设置和查看IPIP地址的分类:IP地址组成: 网络位主机位组成克隆:产生一台新的虚拟机win2008 典型服务模式 • C/S,Client/Server架构 – 由服务器提供资源或某种功能 – 客户机使用资源或功能 TCP/IP 协议 • TCP/IP是最广泛支持的通信协议集合…

java基础知识(Math类)

引入&#xff1a;Math 类包含用于执行基本数学运算的方法&#xff0c;如初等指数、对数、平方根 import java.util.Math 1.abs绝对值 int abs Math.abs(-9); 2.pow求幂 double pow Math.pow(2,4); 3.向上取整 double ceil Math.ceil(3.9);//ceil 4 4.向下取整 dou…

什么是 WPF 中的依赖属性?有什么作用?

依赖属性&#xff08;Dependency Property&#xff09;是 WPF 的一个核心概念&#xff0c;它为传统的 .NET 属性提供了增强功能&#xff0c;支持绑定、样式、动画和默认值等功能。通过依赖属性&#xff0c;WPF 提供了一种灵活的数据驱动的方式来处理 UI 属性。 1. 什么是依赖属…

线性代数空间理解

学习线性代数已经很久&#xff0c;但是在使用过程中仍然还是不明所以&#xff0c;比如不知道特征向量和特征值的含义、矩阵的相乘是什么意思、如何理解矩阵的秩……。随着遇到的次数越来越多&#xff0c;因此我决定需要对线性代数的本质做一次深刻的探讨了。 本次主要是参考了3…

Jmeter的组件执行顺序

在 Apache JMeter 中&#xff0c;组件的加载和执行顺序遵循一定的规则&#xff0c;但有些组件在同一层级中可能会根据它们在测试计划中的位置来决定具体的执行顺序。以下是这些组件的大致加载和执行顺序&#xff0c;以及哪些组件属于同一层级&#xff1a; 线程组&#xff08;Th…

计算机网络八股整理(一)

计算机网络八股文整理 一&#xff1a;网络模型 1&#xff1a;网络osi模型和tcp/ip模型分别介绍一下 osi模型是国际标准的网络模型&#xff0c;它由七层组成&#xff0c;从上到下分别是&#xff1a;应用层&#xff0c;表示层&#xff0c;会话层&#xff0c;传输层&#xff0c;…

今天你学C++了吗?——C++中的类与对象(第二集)

♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥ ♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥ ♥♥♥我们一起努力成为更好的自己~♥♥♥ ♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥ ♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥ ✨✨✨✨✨✨ 个…

【C++习题】14.滑动窗口_找到字符串中所有字母异位词

文章目录 题目链接&#xff1a;题目描述&#xff1a;解法C 算法代码&#xff1a;图解 题目链接&#xff1a; 438. 找到字符串中所有字母异位词 题目描述&#xff1a; 解法 暴力解法&#xff1a; 字母排序后运用滑动窗口解题。 滑动窗口哈希表&#xff1a; 我们可以优化一下&am…

Spring Boot集成MyBatis-Plus:自定义拦截器实现动态表名切换

Spring Boot集成MyBatis-Plus&#xff1a;自定义拦截器实现动态表名切换 一、引言 介绍动态表名的场景需求&#xff0c;比如多租户系统、分表分库&#xff0c;或者不同业务模块共用一套代码但操作不同表。说明 MyBatis-Plus 默认绑定固定表名的问题。 二、项目配置 1. 集成 M…

深入探索API爬虫工作的技术难点与高效解决思路

在大数据与信息化高速发展的今天&#xff0c;API&#xff08;应用程序编程接口&#xff09;爬虫成为了数据收集与分析的重要工具。然而&#xff0c;API爬虫工作并非一帆风顺&#xff0c;它面临着诸多技术挑战。本文将深入探讨几个API爬虫工作的技术难点&#xff0c;并提出相应的…

css效果

css炫彩流光圆环效果 <!DOCTYPE html> <html><head><meta charset"utf-8" /><title></title><style>*{margin: 0;padding: 0;}body{width: 100%;height: 100vh;}.container{position: relative;width: 100%;height: 100vh…

arm Rk1126 编译Qt工程报错: Could not find qmake spec

首先修改qmake.conf文件&#xff0c;配置好正确的交叉编译工具&#xff1a; 然后执行编译&#xff1a; /opt/Rv1126/Rv1126-盒子代码/rv1126-qt5-sdk/bin/qmake untitled.pro 报错。 原因&#xff1a;中文路径。修改路径为英文路径即可

zabbix监控进程

使用zabbix监控指定的进程&#xff0c;现在主要使用监控一些用java python写的一些微服务模块&#xff0c;我这边用于演示就直接使用nginx服务来演示了 创建监控项 name - 进程名称&#xff08;默认为 ALL PROCESSES);user - 用户名&#xff08;默认为 all users);state - 可能…

php 导出excel 一个单元格 多张图片

public function dumpData(){error_reporting(0); // 禁止错误信息输出ini_set(display_errors, 0); // 不显示错误$limit $this->request->post(limit, 20, intval);$offset $this->request->post(offset, 0, intval);$page floor($offset / $limit) 1 ;$wh…

【C++11】锋芒毕露

(续) 一、可变参数模板 C11支持可变参数模板&#xff0c;也就是说支持可变数量参数的函数模板和类模板&#xff0c;可变数目的参数被称 为参数包&#xff0c;存在两种参数包&#xff1a;模板参数包&#xff0c;表示零或多个模板参数&#xff1b;函数参数包&#xff1a;表示零…

用户管理(MySQL)

目录 1用户管理&#xff08;MySQL&#xff09; 1.1 用户 1.1.1 用户信息 1.1.2 创建用户(后%是可以任意远端登录) 1.1.3 刷新一下 1.1.4 删除用户 1.1.5 修改用户密码 1.2 数据库的权限 1.2.1 登录创建用户 1.2.2给权限 1.2.2.1 把jj数据库中uu表的权限给woaini这个…

Hive离线数仓结构分析

Hive离线数仓结构 首先&#xff0c;在数据源部分&#xff0c;包括源业务库、用户日志、爬虫数据和系统日志&#xff0c;这些都是数据的源头。这些数据通过Sqoop、DataX或 Flume 工具进行提取和导入操作。这些工具负责将不同来源的数据传输到基于 Hive 的离线数据仓库中。 在离线…