组件化是客户端上代码复用的架构设计理念和开发模式,将一个复杂的客户端应用按照功能、业务逻辑或者界面展示等维度,拆分成多个相对独立、可复用的组件。每个组件都有自己清晰的边界,包含了特定的业务逻辑、UI 呈现、数据处理等功能,并且可以像搭积木一样被灵活组合到不同的应用模块或者整个应用当中,共同构建起完整的客户端系统。
一、通用的组件化思路
如上图,基本思路是分层和解耦,最上层是壳app,中间层是功能组件,底层是基础组件。分层之后下层组件不能访问上层组件,同层组件直接通过路由跳转页面或者调用方法。
二、鸿蒙上的组件化思路
基于这个方向,鸿蒙在项目结构上也按products、features、commons分为三个目录,对应上面的壳工程、功能组件和基础组件。
2.1products层
products也就是壳工程,如果在单hap的场景下,可以简单理解成entry模块,可以在devEco上选择该entry直接运行,跑出来的就是这个app了。
如果有多个壳工程都放在products下,也就是有多个entryA、entryB、entryC等,由于entry唯一性,其他模块也可以用featrue的type(有个小缺点就是feature没法覆盖entry)
根据每个app依赖的功能组件不同,在对应模块的oh-package.json5里面依赖对应的功能组件(源码或者远端组件均可)
{
"name": "entry",
"version": "1.0.0",
"description": "Please describe the basic information.",
"main": "",
"author": "",
"license": "",
"dependencies": {
"FA": "file:../../features/FA",
"FB": "file:../../features/FB",
"FC": "file:../../features/FC",
}
}
2.2features层
features层也就是功能组件层,这里每个功能组件的类型是har,也就是可以当做sdk提供出去。
功能组件依赖的基础组件也像上面oh-package.json5依赖上即可。
{
"module": {
"name": "FA",
"type": "har",
"deviceTypes": [
"default",
"tablet",
"2in1"
]
}
}
2.3commons层
commons层也就是基础组件层,这里有的组件是har,有的用来中转的组件是hsp。
到了commons层已经不能其他项目中的组件了,只能依赖一些三方库。
hsp的组件如下:
{
"module": {
"name": "commonA",
"type": "shared",
"deviceTypes": [
"phone",
"tablet",
"2in1"
],
"deliveryWithInstall":true
}
}
三、路由以及hsp
3.1路由组件:
项目分层解耦后需要解决的第一个问题是组件之间如何通信。比如FeatureA需要跳到FeatureB的页面,FeatureB需要调用FeatureC的方法。
3.1.1页面跳转
先说页面跳转
鸿蒙框架提供了同名的router类,可以通过router.replaceNamedRoute或者pushNamedRoute实现在har间页面的跳转(即使har没法像hap那样注册main_pages.json也是可以通过这个方法跳转),前提是要把目标页面import进来
但是FeatureA和B互相不可见,也就没法import目标页面,没法直接跳转。
3.1.2方法调用
这时候就需要通过方法调用来实现
原理其实比较简单,通过回调就可以实现。有个公共的底层模块一般叫路由,上层模块都依赖他,并且把自己的方法声明到路由中,具体的实现在自己模块实现。在本模块需要调用其他模块的方法时,先去路由中找方法声明,如果找到了,说明有模块声明并且实现了它,就可以调用该该方法,由目标模块返回结果。
下面是个简单的示例图:
ABCD都把自己的方法声明在router模块,然后各自实现自己声明的方法。
如果A想要调用C的方法,如下图
再回到页面跳转的问题,如果A想要跳转C的页面,只需要funCImpl是通过router.pushNameRoute跳转即可,因为已经在C内部了,可以importC的页面。
3.2 hsp组件
再说一个问题为什么common组件有个需要是hsp,就比如上面提到的路由组件,如果是har那么会被打到ABCD每个模块都有一份,这是再想A去调用C的方法,就会惊讶的发现funC没有实现,去检查代码又发现C模块实现了funC的。因为此时A访问的router和C访问的router都不是同一个对象(即使在项目中定义成单例也没效果),有点类似安卓中的两个进程的对象这样。
为了解决这个问题,就需要把路由组件定义成hsp。当然hsp还有其他特性(如减小体积),这里是为了解决同一份对象的问题。hsp也分应用内hsp和集成态hsp,主要看使用场景如果hsp需要给不同的appid应用使用,就需要集成态hsp。
最后的鸿蒙组件化的整体结构是这样,从上到下是hap、har、har+hsp
作者:Dynamic48570
链接:https://juejin.cn/post/7447049768680587298?searchId=20241213144554E7E96636F3A55F852E2F
暂无评论内容