【HarmonyOS NEXT】鸿蒙中实现组件化通信解耦

1、前言

在鸿蒙项目初期开发中,我们的代码结构可能是这样,features功能模块目录中,涉及到所有功能模块都调用的功能,都放到【公共功能】har中。但是,随着功能的不断增加,和时间推移。这种结构可能会有以下几种问题。

  1. 公共功能har,代码臃肿,业务耦合严重,维护成本增加
  2. 公共功能har,功能无法拆分,假如有手机、手表、汽车三种产品。公共功能har中不同产品可能需要得功能也是不一样的。无法做到产品功能隔离
  3. 实现一个功能,还要去改动很多别人模块的代码?
  4. 修改某个历史功能,但不知不觉导致其他模块出现bug?
    在这里插入图片描述

有没有方法能完全隔离各功能之间的业务模块,通讯之间通过一定协议规则来约束,业务部门开发过程中只专注自己的模块,从物理上杜绝跨业务修改代码?

2、组件化理解

组件化,去除模块间Module[har]的耦合,使得每个业务模块Module[har]可以独立当做App[通过hap壳工程引入]存在,对于其他模块没有直接的依赖关系。 此时业务模块就成为了业务组件。

除了业务组件,还有抽离出来的业务基础组件,是提供给业务组件使用,但不是独立的业务,例如分享组件、广告组件;还有基础组件,即单独的基础功能,与业务无关,例如 图片加载、网络请求等。

组件化带来的好处

  1. 提高协作效率:解耦 使得组件之间 彼此互不打扰,组件内部代码相关性极高。 团队中每个人有自己的责任组件,不会影响其他组件;降低团队成员熟悉项目的成本,只需熟悉责任组件即可;对测试来说,只需重点测试改动的组件,而不是全盘回归测试。
  2. 功能重用:组件 类似我们引用的第三方库,只需维护好每个组件,一建引用集成即可。业务组件可上可下,灵活多变;而基础组件,为新业务随时集成提供了基础,减少重复开发和维护工作量。

下图是我们期望的组件化架构

在这里插入图片描述

  1. 组件依赖关系上层依赖下层,修改频率上层高于下层。
  2. 基础组件是通用基础能力,修改频率极低,作为SDK可共公司所有项目集成使用。
  3. module_common组件,作为支撑业务组件、业务基础组件的基础,同时依赖所有的基础组件,提供多数业务组件需要的基本功能,并且统一了基础组件的版本号。所以 业务组件、业务基础组件 所需的基础能力只需要依赖common组件即可获得。【组件化通信的核心就是common 组件】
  4. 业务组件、业务基础组件,都依赖common组件。但业务组件之间不存在依赖关系,业务基础组件之间不存在依赖关系。而 业务组件 是依赖所需的业务基础组件的,例如几乎所有业务组件都会依赖广告组件 来展示Banner广告、弹窗广告等。

3、 组件化开发的问题点

在深入探讨组件化的原则与策略之际,我们已然领悟到了组件化理念的核心所在,以及其所蕴含的优势与结构特性。在此之后,倘若我们欲将组件化的理念付诸实践,首要的任务便是清晰地界定我们需要解决的一系列挑战。

首要任务是确保业务组件的解耦性。解耦性,乃是构建一个健壯、可维护系统的关键。在此过程中,我们首先需识别可能存在的耦合形式,举例来说,即是页面间的导航跳转、方法之间的互相调用,以及不同组件间的事件通讯机制。显而易见,对于基本组件及业务基础组件,这些耦合问题并非其首要挑战,故此我们可以将其视为封装成库的候选之列,从而实现代码的复用与模块化管理。

然而,当我们的目光转向业务组件时,问题则更为复杂。对于这一层面,我们需面对的问题庞杂且具体,具体细节如下:

  1. 各业务组件并无牵连,如何实现画面间的顺畅跳转?
  2. 在没有相互依赖的前提下,各组件应如何实现通信与方法的相互调用?
    接下来,让我们一探究竟,解答上述诸多疑惑。

3.1 页面跳转

使用框架ZRouter,ZRouter是基于Navigation系统路由表和Hvigor插件实现的动态路由方案。
两行代码就可以完成页面的跳转,如下:
在这里插入图片描述

新建三个模块分别是harA、harB、hspC,三者之间没有依赖关系,entry模块依赖了这三个模块,通过ZRouter可以在四个模块间相互跳转,从而达到模块解耦效果。模块关系图如下图:

在这里插入图片描述

更多详细用法可见:https://juejin.cn/post/7394094789287067685

3.2 组件化通信

组件之间虽缺乏直接依赖,互通却又势在必行。譬如,主页须展示购物车内物品之数目,然查询此数目之能,独属于购物车组件之内部。于此情形,我们该如何是好呢?

3.2.1 新建组件通信服务module

也可以不用新建,放到module_common也行
library_service

IClassConstructor.ts
/**
 * 用于拿到Class 类,然后实例化
 * @author Tanranran
 * @description
 */
export interface IClassConstructor<T> 
<think>我们注意到用户的问题集中在鸿蒙开发中的组件间通信,特别是层级较深的最上层和最下层组件之间的通信。用户提到了“wrapbuilder”,但根据之前的回答,WrapBuilder并非鸿蒙官方组件,可能是用户对某种通信方式的误解或混淆。结合引用内容:-引用[1]和[3]提到了组件化通信解耦,说明在鸿蒙开发中,组件化通信是一个重要主题。-引用[2]提到了页面间共享组件实例的案例,这涉及到组件实例的共享和通信。用户的问题可以分解为:1.鸿蒙中如何实现深层嵌套组件的通信(从最上层到最下层)?2.用户提到的“wrapbuilder”是否与鸿蒙中的某种通信机制有关?但根据之前的分析,WrapBuilder在鸿蒙中并不存在。因此,我们重点解决第一个问题。在鸿蒙HarmonyOS)中,实现深层组件通信的常用方法有:1.**Prop传值**:通过父组件逐层传递数据,但层级过深时繁琐且易耦合。2.**@Provide和@Consume装饰器**:用于跨层级数据同步,提供者组件(通常是祖先节点)通过@Provide提供数据,后代组件通过@Consume获取并监听变化,实现解耦[^1][^3]。3.**@Observed和@ObjectLink装饰器**:用于嵌套对象或数组的跨组件同步,适用于复杂数据结构。4.**EventHub(事件中心)**:通过全局事件总线进行通信,任意组件可订阅或发布事件,但需注意事件命名冲突和生命周期管理。5.**AppStorage/应用全局状态**:全局单例对象,所有组件可访问和监听变化,适合全局状态管理(如用户信息)[^1]。由于用户场景是“最上层和最下层组件”,即跨越多层,推荐使用@Provide/@Consume或AppStorage。下面以@Provide/@Consume为例说明:假设有一个深层嵌套结构:`A>B>C>D`,其中A是最上层组件,D是最下层组件。A需要传递数据到D,并可能接收D的更新。步骤:1.在A组件中,使用`@Provide`装饰器提供数据。2.在D组件中,使用`@Consume`装饰器消费数据。示例代码(ArkTS):```typescript//在A组件中@ComponentstructA{@Providemessage:string='HellofromA';//提供数据build(){Column(){B()//子组件B}}}//B组件包含C,C包含D@ComponentstructB{build(){Column(){C()}}}@ComponentstructC{build(){Column(){D()}}}//最下层的D组件@ComponentstructD{@Consumemessage:string;//消费A提供的数据build(){Text(this.message)//显示来自A的数据.onClick(()=>{this.message='Dclicked!';//修改数据,会反向同步到A})}}```当D组件中的点击事件修改`message`时,A组件中的`message`也会更新,实现了双向同步[^1][^3]。对于更复杂的场景(如多个页面共享状态),可以使用AppStorage:```typescript//在任意组件中设置全局状态AppStorage.SetOrCreate<string>('globalMessage','Initialvalue');//在D组件中获取和修改@ComponentstructD{@StorageLink('globalMessage')message:string;//关联AppStorage中的keybuild(){Text(this.message).onClick(()=>{this.message='UpdatedbyD';})}}```关于“wrapbuilder”,根据用户的问题,我们推测可能是指某种包装构建器,但在鸿蒙中,如果是指构建UI组件,通常使用`@Builder`装饰器,但它用于构建UI片段,不直接用于通信。因此,深层通信应优先选择上述方法。总结:-对于父子层级较少的通信,使用Prop传值。-对于深层嵌套组件通信,优先使用`@Provide`和`@Consume`。-对于全局状态,使用AppStorage或LocalStorage。-避免使用事件总线(如EventHub)导致难以维护,除非必要。因此,针对用户问题,推荐使用@Provide/@Consume或AppStorage实现上下层组件通信,而WrapBuilder并非鸿蒙官方通信机制,可忽略。§§相关问题§§1.鸿蒙中@Provide和@Consume装饰器的底层原理是什么?2.如何避免AppStorage全局状态管理导致的性能问题?3.鸿蒙组件化开发中,如何设计高内聚低耦合的组件?</think>在鸿蒙HarmonyOS NEXT)开发中,实现深度嵌套组件(最上层和最下层)之间的高效通信,推荐使用以下方案,结合组件化解耦思想: ### 核心通信方案(无需WrapBuilder) #### 1. **@Provide/@Consume装饰器**(跨层级双向通信) ```typescript // 顶层组件(提供数据) @Component struct TopComponent { @Provide message: string = "Hello from Top" build() { Column() { MiddleComponent() } } } // 中间层组件(无需传递) @Component struct MiddleComponent { build() { Column() { BottomComponent() } } } // 底层组件(消费数据) @Component struct BottomComponent { @Consume message: string build() { Text(this.message) // 直接显示顶层数据 .onClick(() => { this.message = "Updated from Bottom" // 反向更新顶层数据 }) } } ``` **优势**: - 自动建立跨层级绑定关系,无需中间组件传递 - 支持双向数据同步(底层修改自动通知顶层) - 符合组件化解耦原则[^3] #### 2. **AppStorage全局状态管理** ```typescript // 全局状态定义 AppStorage.SetOrCreate<string>('globalMsg', 'Initial Value') // 顶层组件(修改状态) AppStorage.Set<string>('globalMsg', 'New Value from Top') // 底层组件(监听状态) @Component struct BottomComponent { @StorageLink('globalMsg') msg: string build() { Text(this.msg) .onClick(() => { this.msg = "Updated from Bottom" }) } } ``` **适用场景**: - 跨页面组件通信 - 全局状态共享(如用户信息、主题设置)[^1] #### 3. **EventHub事件中心** ```typescript // 初始化事件中心(在EntryAbility中) import emitter from '@ohos.events.emitter' // 顶层组件发布事件 emitter.emit({ eventId: 1, priority: emitter.EventPriority.HIGH }, { data: { command: "refresh" } }) // 底层组件订阅事件 emitter.on(1, (eventData) => { console.log("Received:", eventData.data.command) }) ``` **最佳实践**: - 定义统一事件ID常量文件 - 在组件`aboutToDisappear`中取消订阅 - 适用于一次性指令传递(非持续状态)[^1] ### 关于WrapBuilder的说明 1. **非官方概念**:鸿蒙官方文档中无`WrapBuilder`定义,可能混淆了: - `@Builder` UI构建装饰器(用于组件复用) - `Wrap` 流式布局组件(与通信无关) 2. **通信替代方案**:上述三种方案已覆盖: - 父子组件:常规Prop传递 - 跨层级:@Provide/@Consume - 全局通信:AppStorage/EventHub ### 性能优化建议 1. **组件更新范围控制**: ```typescript @Component struct OptimizedComponent { @State @Watch('onDataChange') data: DataType onDataChange() { // 仅更新必要部分 } } ``` 2. **大数据量场景**: ```typescript LazyForEach(this.dataArray, (item) => { ChildComponent({item}) }, (item) => item.id) ``` 3. **避免多层Prop透传**: - 超过2层嵌套优先使用@Provide/@Consume - 复杂数据结构用@ObjectLink解耦[^2] > 通过组件化通信解耦,可显著提升协作效率并降低维护成本[^3]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冉冉同学_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值