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

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

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)};@BuilderrouterMap(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.rhkb.cn/news/429110.html

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

相关文章

LabVIEW编程能力如何能突飞猛进

要想让LabVIEW编程能力实现突飞猛进&#xff0c;需要采取系统化的学习方法&#xff0c;并结合实际项目进行不断的实践。以下是一些提高LabVIEW编程能力的关键策略&#xff1a; 1. 扎实掌握基础 LabVIEW的编程本质与其他编程语言不同&#xff0c;它是基于图形化的编程方式&…

行业人工智能研究-Python自监督方式学习图像表示算法

学术界人工智能研究落后于工业界 摘要 行业或工业界在人工智能研究上超出学术界&#xff0c;并占据着大量的计算力&#xff0c;数据集和人才诱人的薪水和明朗的预期吸引大量人才离开学术界&#xff0c;涌入行业或工业界即使&#xff0c;比如Meta开源其人工智能模型&#xff0…

小程序地图展示poi帖子点击可跳转

小程序地图展示poi帖子点击可跳转 是类似于小红书地图功能的需求 缺点 一个帖子只能有一个点击事件&#xff0c;不适合太复杂的功能&#xff0c;因为一个markers只有一个回调回调中只有markerId可以使用。 需求介绍 页面有地图入口&#xff0c;点开可打开地图界面地图上展…

python:编写一个函数查找字符串中的最长公共前缀

最近在csdn网站上刷到一个题目&#xff0c;题目要求编写一个函数查找字符串中的最长公共前缀&#xff0c;题目如下&#xff1a; 给出的答案如下&#xff1a; from typing import List def longestCommonPrefix(strs:List[str]) -> str:if len(strs) 0:return i 0 #代…

2024/9/21 数学20题

常见概率可加性&#xff1a;

网络安全详解

目录 引言 一、网络安全概述 1.1 什么是网络安全 1.2 网络安全的重要性 二、网络安全面临的威胁 2.1 恶意软件&#xff08;Malware&#xff09; 2.2 网络钓鱼&#xff08;Phishing&#xff09; 2.3 中间人攻击&#xff08;Man-in-the-Middle Attack&#xff09; 2.4 拒…

Mac 搭建仓颉语言开发环境(Cangjie SDK)

文章目录 仓颉编程语言通用版本SDK Beta试用报名仓颉语言文档注册 GitCode登录 GitCode 下载 Cangjie SDK配置环境变量VSCode 插件VSCode 创建项目 仓颉编程语言通用版本SDK Beta试用报名 https://wj.qq.com/s2/14870499/c76f/ 仓颉语言文档 https://developer.huawei.com/c…

Redis——持久化策略

Redis持久化 Redis的读写操作都是在内存上&#xff0c;所以Redis性能高。 但是当重启的时候&#xff0c;或者因为特殊情况导致Redis崩了&#xff0c;就可能导致数据的丢失。 所以Redis采取了持久化的机制&#xff0c;重启的时候利用之间持久化的文件实现数据的恢复。 Redis提…

Golang | Leetcode Golang题解之第424题替换后的最长重复字符

题目&#xff1a; 题解&#xff1a; func characterReplacement(s string, k int) int {cnt : [26]int{}maxCnt, left : 0, 0for right, ch : range s {cnt[ch-A]maxCnt max(maxCnt, cnt[ch-A])if right-left1-maxCnt > k {cnt[s[left]-A]--left}}return len(s) - left }f…

PyCharm与Anaconda超详细安装配置教程

1、安装Anaconda&#xff08;过程&#xff09;-CSDN博客 2.创建虚拟环境conda create -n pytorch20 python3.9并输入conda activate pytorch20进入 3.更改镜像源conda/pip(只添加三个pip源和conda源即可) 4.安装PyTorch&#xff08;CPU版&#xff09; 5.安装Pycharm并破解&…

猫咪检测系统源码分享

猫咪检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vision …

USDT自动化交易【Pinoex】【自动化分析】【ChatGPT量化脚本】

Pinoex 是一个相对较新的加密货币交易平台&#xff0c;虽然具体的自动交易算法细节对外部用户可能并不公开&#xff0c;但我们可以讨论一般情况下加密货币自动交易算法的常见策略和方法。以下是一些可能会被类似平台或个人交易者使用的自动交易算法和策略。 1. 市场制造商&…

Google 扩展 Chrome 安全和隐私功能

过去一周&#xff0c;谷歌一直在推出新特性和功能&#xff0c;旨在让用户在 Chrome 上的桌面体验更加安全&#xff0c;最新的举措是扩展在多个设备上保存密钥的功能。 到目前为止&#xff0c;Chrome 网络用户只能将密钥保存到 Android 上的 Google 密码管理器&#xff0c;然后…

计算机网络17——IM聊天系统——客户端核心处理类框架搭建

目的 拆开客户端和服务端&#xff0c;使用Qt实现客户端&#xff0c;VS实现服务端 Qt创建项目 Qt文件类型 .pro文件&#xff1a;配置文件&#xff0c;决定了哪些文件参与编译&#xff0c;怎样参与编译 .h .cpp .ui&#xff1a;画图文件 Qt编码方式 Qt使用utf-8作为编码方…

从零开始学习TinyWebServer

写在前面 项目参考&#xff1a;https://github.com/qinguoyi/TinyWebServer 写作框架/图参考&#xff1a;https://blog.csdn.net/qq_52313711/article/details/136356042?spm1001.2014.3001.5502 原本计划是&#xff0c;先将项目代码大概看一遍&#xff0c;然后再着手实现一下…

《高等代数》线性相关和线性无关(应用)

说明&#xff1a;此文章用于本人复习巩固&#xff0c;如果也能帮到大家那就更加有意义了。 注&#xff1a;1&#xff09;线性相关和线性无关的证明方法中较为常用的方法是利用秩和定义来证明。 2&#xff09;此外&#xff0c;线性相关和线性无关的证明常常也会用到反证法。 3&…

ChatGPT 4o 使用指南 (9月更新)

首先基础知识还是要介绍得~ 一、模型知识&#xff1a; GPT-4o&#xff1a;最新的版本模型&#xff0c;支持视觉等多模态&#xff0c;OpenAI 文档中已经更新了 GPT-4o 的介绍&#xff1a;128k 上下文&#xff0c;训练截止 2023 年 10 月&#xff08;作为对比&#xff0c;GPT-4…

play-with-docker使用指南

Play-with-Docker(PWD)是一个在线平台,提供免费的 Docker 实验环境。它允许用户在浏览器中创建和管理 Docker 容器,适合学习和实验。国内访问需要借助于魔法工具,否则可能无法访问哦。 网站地址:https://labs.play-with-docker.com/ 一、登录play-with-docker 点击页面上…

深度学习自编码器 - 去噪自编码器篇

序言 在深度学习的广阔天地中&#xff0c;自编码器作为一种强大的无监督学习工具&#xff0c;通过重构输入数据的方式&#xff0c;不仅实现了数据的有效压缩&#xff0c;还探索了数据的内在表示。而去噪自编码器&#xff08; Denoising Autoencoder, DAE \text{Denoising Auto…

Java | Leetcode Java题解之第424题替换后的最长重复字符

题目&#xff1a; 题解&#xff1a; public class Solution {public int characterReplacement(String s, int k) {int len s.length();if (len < 2) {return len;}char[] charArray s.toCharArray();int left 0;int right 0;int res 0;int maxCount 0;int[] freq n…