鸿蒙开发(HarmonyOS)组件化浅谈

news2024/9/20 18:17:28

众所周知,现在组件化在移动开发中是很常见的,那么组件化有哪些好处:

1. 提高代码复用性:组件化允许将应用程序的不同功能模块化,使得这些模块可以在不同的项目中重复使用,从而提高开发效率并减少重复工作。

2. 降低组件间的耦合:通过组件化的规则将代码拆分成不同的模块,实现高内聚、低耦合,使得代码更易于维护,降低了模块间的依赖,减少了潜在的错误和问题。

3. 提升开发效率:组件化使得开发团队可以并行工作,每个团队可以专注于自己的组件,独立开发和维护,这样可以加快开发进度,提高整体的开发效率。

4. 改善代码质量:组件化鼓励开发者编写清晰、模块化的代码,有助于提高代码的可读性和可维护性,从而提升代码质量。

5. 便于扩展和迭代:组件化架构使得添加新功能或改进现有功能变得更加容易,有助于快速响应市场变化和用户需求。

6. 隔离技术栈:不同的组件可以使用不同的技术栈,而不会相互影响,使得技术选型更加灵活。

7. 独立开发/维护/发布:组件化允许每个组件独立开发、维护和发布,使得更新和迭代更加灵活。

8. 提高编译/构建速度:组件化使得编译和构建过程更加高效,因为只需要编译和构建相关的组件,而不是整个项目。

9. 管控代码权限:组件化允许更好地控制代码权限,通过将代码分散到不同的仓库中,可以限制对特定组件的访问和修改。

10. 管理版本变更:组件化使得管理版本变更变得更加容易,因为每个组件都有明确的版本,可以更容易地跟踪和控制版本更新。

组件化是解决单一工程架构开发中问题的有效方法,它通过将大型项目拆分成更小、更易于管理的模块,提高了开发效率和代码质量。然而,组件化也带来了一些挑战,如组件粒度的划分、组件间依赖关系的管理以及跨技术栈通信等。为了实现高质量的组件化项目,需要遵循一些实践规范和原则,如组件拆分原则、组件间依赖管理以及质量保障措施。
 

那么我们在进行鸿蒙开发时如何进行组件化开发呢,接下来我将带大家了解鸿蒙开发中的组件化,项目的目录结构如下

其中features目录下是组件/模块,包含不同的功能分区,entity是项目的主入口也就是hap包,commons目录下有3个har组件,分别是utils:所有的帮助类、uicomponents:项目中需要用到的自定义UI组件等、RouterModule:项目的路由(承载了整个项目跨组件通信的能力)

接下来我们重点说一下RouterModule

不同组件之间想要通信,需要建立路由联系,RouterModule模块的实现主要包含以下步骤:

1. 定义路由表和路由栈

export class RouterModule {
  // WrappedBuilder支持@Builder描述的组件以参数的形式进行封装存储
  static builderMap: Map<string, WrappedBuilder<[object]>> = new Map<string, WrappedBuilder<[object]>>();
  // 初始化路由栈,需要关联Navigation组件
  static navPathStack: NavPathStack = new NavPathStack();
}

2. 路由表增加路由注册和路由获取方法,业务har模块通过路由注册方法将需要路由的页面组件委托给RouterModule管理,增加路由跳转方法,业务har模块通过调用该方法并指定跳转信息实现模块间路由跳转,完整代码如下

/**
 * @FileName : RouterModule
 * @Author : kirk.wang
 * @Time : 2024/7/10 10:44
 * @Description : 路由管理
 */
import { RouterModel } from '../model/RouterModel';
import Logger from './Logger';

export class RouterModule {
  static builderMap: Map<string, WrappedBuilder<[object]>> = new Map<string, WrappedBuilder<[object]>>();
  static routerMap: Map<string, NavPathStack> = new Map<string, NavPathStack>();

  // Registering a builder by name.
  public static registerBuilder(builderName: string, builder: WrappedBuilder<[object]>): void {
    RouterModule.builderMap.set(builderName, builder);
  }

  // Get builder by name.
  public static getBuilder(builderName: string): WrappedBuilder<[object]> {
    const builder = RouterModule.builderMap.get(builderName);
    if (!builder) {
      Logger.info('not found builder ' + builderName);
    }
    return builder as WrappedBuilder<[object]>;
  }

  // Registering a router by name.
  public static createRouter(routerName: string, router: NavPathStack): void {
    RouterModule.routerMap.set(routerName, router);
  }

  // Get router by name.
  public static getRouter(routerName: string): NavPathStack {
    return RouterModule.routerMap.get(routerName) as NavPathStack;
  }

  // Jumping to a Specified Page by Obtaining the Page Stack.
  public static async push(router: RouterModel): Promise<void> {
    const harName = router.builderName.split('_')[0];
    // Dynamically import the page to be redirected to.
    await import(harName).then((ns: ESObject): Promise<void> => ns.harInit(router.builderName));
    RouterModule.getRouter(router.routerName).pushPath({ name: router.builderName, param: router.param });
  }

  // Obtain the page stack and pop it.
  public static pop(routerName: string): void {
    // Find the corresponding route stack for pop.
    RouterModule.getRouter(routerName).pop();
  }

  // Get the page stack and clear it.
  public static clear(routerName: string): void {
    // Find the corresponding route stack for pop.
    RouterModule.getRouter(routerName).clear();
  }

  // Directly jump to the specified route.
  public static popToName(routerName: string, builderName: string): void {
    RouterModule.getRouter(routerName).popToName(builderName);
  }
}

3.RouterModel为了方便在页面跳转直接进行传值,完整代码如下:

/**
 * @FileName : RouterModel
 * @Author : kirk.wang
 * @Time : 2024/9/13 14:33
 * @Description : 路由信息类,便于跳转时传递更多信息
 */
import { RouterModule } from '../utils/RouterModule';

export class RouterModel {
  // 路由页面别名
  builderName: string = "";
  routerName: string = "";
  // 需要传入页面的参数
  param?: string = "";
}

// 创建路由信息,并放到路由栈表中
export function buildRouterModel(routerName: string, builderName: string, param?: string) {
  let router: RouterModel = new RouterModel();
  router.builderName = builderName;
  router.routerName = routerName;
  router.param = param;
  RouterModule.push(router);
}

页面跳转实现

路由管理模块RouterModule实现之后,需要使用RouterModule模块实现业务模块harA的页面跳转到业务模块harB的页面功能。主要步骤如下:

  1. 在工程主入口模块Entry.hap中引入RouterModule模块和所有需要进行路由注册的业务har模块。
    // Entry.hap中的oh-package.json5文件
     "dependencies": {
        "@ohos/home": "file:../features/home",
        "@ohos/report": "file:../features/report",
        "@ohos/shopcart": "file:../features/shopcart",
        "@ohos/mine": "file:../features/mine",
        "@ohos/utils": "file:../commons/utils",
        "@ohos/routermodule": "file:../commons/RouterModule"
      }

  2.  在工程主入口模块的首页Navigation组件上关联RouterModule模块的路由栈和路由表。

    import HomeTabs from './HomeTabs'
    import { BuilderNameConstants, buildRouterModel, RouterModule, RouterNameConstants } from '@ohos/routermodule';
    
    @Preview
    @Entry
    @Component
    struct Index {
      @State homeTab: number = 0
      @State entryHapRouter: NavPathStack = new NavPathStack();
    
      aboutToAppear() {
        if (!this.entryHapRouter) {
          this.entryHapRouter = new NavPathStack();
        }
        RouterModule.createRouter(RouterNameConstants.ENTRY_HAP, this.entryHapRouter)
      };
    
      @Builder
      routerMap(builderName: string, param: object) {
        // 从RouterModule中获取全局路由表
        RouterModule.getBuilder(builderName).builder(param);
      }
    
      build() {
        // 绑定RouterModule中路由栈
        Navigation(this.entryHapRouter) {
          Column() {
            HomeTabs({ currentIndex: this.homeTab })
          }.backgroundColor('#f1f3f5').width('100%').height('100%')
        }
        .navDestination(this.routerMap); // 从RouterModule中获取全局路由表
      }
    }
  3. 在har中声明需要跳转的页面,并且调用registerBuilder接口将页面注册到RouterModule模块的全局路由表上。以下注册逻辑会在harB的B1页面被首次加载时触发

    // harhome模块的登录页面
    import { CommonConstants } from '@ohos/utils';
    import router from '@ohos.router';
    import { BuilderNameConstants, buildRouterModel, RouterModule, RouterNameConstants, } from '@ohos/routermodule';
    
    
    @Builder
    export function harBuilder(value: object) {
      NavDestination() {
        Column() {
          ///...
          }.backgroundColor($r('app.color.page_background'))
        }
        .width('100%')
        .height('100%')
      }
      .title('登录')
      .onBackPressed(() => {
        RouterModule.pop(RouterNameConstants.ENTRY_HAP);
        return true;
      })
    }
    
    const builderName = BuilderNameConstants.MINE_LOGIN;
    if (!RouterModule.getBuilder(builderName)) {
      let builder: WrappedBuilder<[object]> = wrapBuilder(harBuilder);
      RouterModule.registerBuilder(builderName, builder);
    }
    
  4. 在harHome模块中的页面调用RouterModule模块的push方法实现跳转到harMine的Login页面。当harMine的Login页面被首次通过push方法跳转时,会动态加载Login页面,并且触发步骤3中Login页面的路由注册逻辑,把Login页面注册到RouterModule的全局路由表builderMap中。

    import { BuilderNameConstants, buildRouterModel, RouterModule, RouterNameConstants, } from '@ohos/routermodule';
    
    @Entry
    @Component
    export struct HomePage {
      build() {
        Column() {
          Button('go loagin', { stateEffect: true, type: ButtonType.Capsule })
            .width('80%')
            .height(40)
            .margin(20)
            .onClick(() => {
              buildRouterModel(RouterNameConstants.ENTRY_HAP, BuilderNameConstants.MINE_LOGIN);
            })
        }.width('100%').height('100%').backgroundColor('#F1F3F5')
      }
    }

上述方案,当在entry模块页面上点击跳转到harA模块的页面时序图如下:

具体实现

在harMine的对外导出类Index.ets中定义加载时的初始化函数harInit,该函数对harMine中需要注册路由的页面组件进行加载管理,被调用时将根据不同的路径动态加载不同的页面。as

import { BuilderNameConstants } from '@ohos/routermodule';

export { MinePage } from './src/main/ets/components/mainpage/MinePage'

export function harInit(builderName: string): void {
  // 动态引入要跳转的页面
  switch (builderName) {
    case BuilderNameConstants.MINE_ORDERLIST:
      import("./src/main/ets/components/mainpage/OrderListPage");
      break;
    case BuilderNameConstants.MINE_LOGIN:
      import("./src/main/ets/components/mainpage/LoginPage");
      break;
    case BuilderNameConstants.MINE_TEST:
      import("./src/main/ets/components/mainpage/test");
      break;
    default:
      break;
  }
}

最后在Hap工程的build-profile.jsn5中添加所有的动态库

  "buildOption": {
    "arkOptions": {
      "runtimeOnly": {
        "sources": [
        ],
        "packages": [
          "@ohos/home",
          "@ohos/report",
          "@ohos/shopcart",
          "@ohos/mine",
          "@ohos/utils",
          "@ohos/routermodule"
        ]
      }
    }
  },

接下来在点击主页的登录按钮,就能实现从主页跳转到登录页,返回后依然能返回到前面的页面。更多功能同学们可以继续探索,官方文档地址:文档中心

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

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

相关文章

JAVA并发编程系列(9)CyclicBarrier循环屏障原理分析

拼多多2面&#xff0c;还是模拟拼团&#xff0c;要求用户拼团成功后&#xff0c;提交订单支付金额。 之前我们在系列(8)《CountDownLatch核心原理》&#xff0c;实现过拼团场景。但是CountDownLatch里调用countDown()方法后&#xff0c;线程还是可以继续执行后面的代码&#xf…

【云安全】云上资产发现与信息收集

一、云基础设施组件 1、定义 在云计算基础架构中&#xff0c;基础设施组件通常包括&#xff1a;计算、存储、网络和安全等方面的资源。例如&#xff0c;计算资源可以是虚拟机、容器或无服务器计算引擎&#xff1b;存储资源可以是对象存储或块存储&#xff1b;网络资源可以是虚拟…

数字电路与逻辑设计-计数器逻辑功能测试

一&#xff0e;实验目的 1&#xff0e;验证用触发器构成的计数器计数原理&#xff1b; 2&#xff0e;掌握测试中规模集成计数器功能的方法&#xff1b; 二&#xff0e;实验原理 时序逻辑电路中&#xff0c;有一种电路称为计数器&#xff0c;计数器是用来对时钟脉冲进行计数的…

稳联Profinet转Canopen网关携手伺服,高效提升生产效率

在当今的工业生产领域&#xff0c;追求高效、精准和可靠的生产方式是企业不断努力的方向。稳联技术Profinet转Canopen&#xff08;WL-ABC3033&#xff09;网关与伺服系统的携手合作&#xff0c;为提高生产效率带来了新的机遇和突破。 实现无缝通信&#xff0c;优化生产流程稳联…

Flink提交任务

第3章 Flink部署 3.1 集群角色 3.2 Flink集群搭建 3.2.1 集群启动 0&#xff09;集群规划 表3-1 集群角色分配 具体安装部署步骤如下&#xff1a; 1&#xff09;下载并解压安装包 &#xff08;1&#xff09;下载安装包flink-1.17.0-bin-scala_2.12.tgz&#xff0c;将该jar包…

无人机之控制距离篇

无人机的控制距离是一个复杂且多变的概念&#xff0c;它受到多种因素的共同影响。以下是对无人机控制距离及其影响因素的详细分析&#xff1a; 一、无人机控制距离的定义 无人机控制距离指的是遥控器和接收机之间的最远传输距离。这个距离决定了无人机在操作者控制下能够飞行的…

2024年氧化工艺证考试题库及氧化工艺试题解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年氧化工艺证考试题库及氧化工艺试题解析是安全生产模拟考试一点通结合&#xff08;安监局&#xff09;特种作业人员操作证考试大纲和&#xff08;质检局&#xff09;特种设备作业人员上岗证考试大纲随机出的氧化…

VM+Ubuntu16.04硬盘扩容

步骤&#xff1a; 用df -h查看自己虚拟机的硬盘空间使用情况在虚拟机下安装gparted软件备用 sudo apt-get install gparted在VM的界面或者Windows终端修改虚拟机硬盘大小回到虚拟机的gparted软件里&#xff0c;修改分区&#xff0c;先删除原有的逻辑分区和扩展分区&#xff0c…

一键快速替换PPT上的字体?这个你一定要学会。

前言 最近有个朋友在做PPT&#xff0c;说是准备在各大平台分发&#xff0c;咨询小白关于PPT上内容的事情&#xff0c;结果小白问了一句&#xff1a;字体用的是什么&#xff1f; 嗯……她说是&#xff1a;汉仪黑和字魂。 好家伙&#xff0c;这不是妥妥的当别人财神爷的机会吗&…

是的,第一个在Domino中整个AI本地大语言模型的开源项目已经发布

大家好&#xff0c;才是真的好。 做梦也没想到&#xff0c;上一篇《Notes&#xff0c;无代码应用开发王者归来&#xff01;》居然又一次焕发了卓越的青春活力&#xff0c;阅读量超高。真希望能再接再厉&#xff0c;续创辉煌。 但今天咱们怎么也不能再讲HCL Notes/Dmino 14.5 …

Vue3 : Pinia的性质与作用

目录 一.性质 二.作用 三.Pinia 的核心概念 四.使用 1.count.ts 2.count.vue Vue 3 中 Pinia 是一个专为 Vue 3 设计的状态管理库&#xff0c;它旨在提供一种简单、直观的方式来管理应用的状态。 一.性质 1.集成性&#xff1a;Pinia 是 Vue 3 官方推荐的状态管理库&…

Linux C高级 day2

一、 1.mkdir ../dir1 && touch ../dir/file 2.cp -r /mnt/dir1/* /home/dir2 3.pwd 4.ls -l 5.ip或ifconfig 6.top 7.ps aux | grep python 8.kill -9 7580 9.ping 10.find /usr -type f -name *name* 11. a-> 输入内容->ese->shift冒号 wq回车 …

JAVA-期末成绩计算

要求 总评成绩 期末成绩*0.6 平时成绩*0.4 输入总评成绩和平时成绩&#xff0c;输出期末成绩要考几分&#xff08;0<平时成绩<40&#xff0c;0<总评成绩<100&#xff09; 要求能多次运行&#xff08;退出程序停止&#xff09; 代码 import java.util.Scanne…

Java 多态(难)

1. 即同一方法可以根据发送对象的不同而采用多种不同的行为方式。 2&#xff0e;一个对象的实际类型是确定的&#xff0c;但可以指向对象的引用的类型有很多。 举例说明&#xff1a;新建两个类&#xff0c;Person类和Student类&#xff0c;Student类继承Person类&#xff1a…

背景图鼠标放上去切换图片过渡效果

文章目录 css鼠标放上去之前效果鼠标放上去时效果 css <li class"message"></li>.message {width: 22px;height: 22px;background-image: url(/assets/message-01.png);background-size: cover;background-position: center;transition: background-ima…

化工行业如何做数字化转型?

据红杉的一项调查报告中指出&#xff0c;国内超九成的企业&#xff08;95%&#xff09;已经开展了不同程度的数字化实践&#xff0c;并将把数字化转型作为企业的战略核心。数字化转型或者说通过数据手段来帮助企业更好发展的方式&#xff0c;已成为未来不可避免的趋势。 那么&a…

中英混杂 Style Error: [China National Standard GB/T 7714-1987 (numeric, 中文)]

Style Error: [China National Standard GB/T 7714-1987 (numeric, 中文)] etc. - Zotero ForumsStyle Error: [China National Standard GB/T 7714-1987 (numeric, 中文)] etc. 问题描述 最近发现使用zotero插入参考文献时英文的被识别成中文格式了&#xff0c;所以引用格式…

动手学深度学习(pytorch土堆)-06损失函数与反向传播、模型训练、GPU训练

模型保存与读取 完整模型训练套路 import torch import torchvision.datasets from torch import nn from torch.nn import Conv2d, MaxPool2d, Flatten, Linear from torch.utils.data import DataLoader from torch.utils.tensorboard import SummaryWriterfrom model impo…

基于多域名,通过云运营商弹性负载,Nginx配置等基于的多租户系统部署

已经开发好久的系统&#xff0c;因为业务上没有需求&#xff0c;没有做上线部署&#xff0c;此系统为多租户系统&#xff0c;原来设计是通过租户码参数来识别的&#xff0c;每个租户访问&#xff0c;需要传自己的码过来&#xff0c;才能确定是哪个租户登录系统&#xff0c; 今…

深度学习(一)——CMC特刊推荐

点击蓝字 关注我们 特刊征稿 01 期刊名称&#xff1a; Multimedia Security in Deep Learning 截止时间&#xff1a; 提交截止日期:2024年9月30日 目标及范围&#xff1a; 题为“深度学习中的多媒体安全”的特刊是一个平台&#xff0c;旨在推动深度学习在多媒体安全领域的创…