HarmonyOS 应用开发《掌上英语》第68篇:组件复用实战——通用组件在各模块中的引用分析

组件复用实战——通用组件在各模块中的引用分析

一、组件复用的价值

在 11 模块架构中,组件复用是减少代码重复、保持 UI 一致性的关键策略。通过将通用 UI 组件提取到 commonLib 模块,所有 feature 和 component 模块都可以共享这些组件,而无需在每个模块中重复实现。

组件复用的主要收益:

  1. 开发效率提升:一次实现,多处使用,减少重复编码
  2. UI 一致性:所有页面使用相同的 TopBar、CommonHeader,视觉风格统一
  3. 维护成本降低:组件修改只在 commonLib 中进行,所有引用自动更新
  4. Bug 减少:经过多模块验证的组件,质量更有保障

二、TopBar 组件的跨模块复用

TopBar是最基础的复用组件,位于commons/commonLib/src/main/ets/components/TopBar.ets

@ComponentV2exportstruct TopBar{@Paramtitle:string|Resource='';@ParamonClickBack:()=>void=()=>{}build(){Row(){Row(){Image($r('app.media.ic_back')).width($r('app.float.vp_40')).height($r('app.float.vp_40')).borderRadius($r('app.float.vp_20')).onClick(()=>{this.onClickBack()})}.width($r('app.float.vp_40')).height($r('app.float.vp_40')).borderRadius($r('app.float.vp_20')).backgroundColor($r('sys.color.background_secondary'))Text(this.title).fontSize($r('sys.float.Title_S')).fontWeight(FontWeight.Medium).fontColor($r('sys.color.font_primary')).margin({left:$r('app.float.vp_8')})}}}

TopBar 的设计特点:

  • 使用@Param接收输入(title、onClickBack),不管理内部状态
  • 默认提供空的onClickBack实现,调用方可以选择不传
  • 通过$r引用公共资源,不依赖特定模块的资源

TopBar 在 homePage 的引用方式:

import{TopBar}from'commonlib';// 在首页中使用TopBar({title:'英语学习',onClickBack:()=>RouterModule.pop()})

TopBar 在 topicPage 的引用:

TopBar({title:'单词卡片',onClickBack:()=>RouterModule.pop()})

同一个 TopBar 组件,通过传入不同的 title,服务于不同的页面。

三、CommonHeader 组件

CommonHeader(即TopTabsBuilder)是另一种结构的头部组件,提供了更多的功能选项:

@ComponentV2exportstruct TopTabsBuilder{@Paramtitle:string='';@ParambgColor:ResourceStr=$r('sys.color.background_secondary');@ParamshowBackButton:boolean=false;@Paramtype:string='一级建造师';@Localindex:number=0;}// 使用示例TopTabsBuilder({title:'我的课程',showBackButton:true,type:'英语学习'})

CommonHeader 比 TopBar 更复杂,支持:

  • 搜索按钮
  • 下拉选择
  • 自定义背景色
  • 可选的返回按钮

四、Banner 组件的复用

Banner 轮播图组件同样位于 commonLib:

@ComponentV2exportstruct Banner{@ParambannerArray:Array<ResourceStr>=[$r('app.media.banner1'),];@LocalbreakpointModel:BreakpointModel=AppStorageV2.connect(BreakpointModel,...)!;swiperDisplayCount:BreakpointType<number>=newBreakpointType<number>({sm:1,md:2,lg:3,xl:3,});build(){Column(){Swiper(){ForEach(this.bannerArray,(item:ResourceStr)=>{Image(item).interpolation(ImageInterpolation.High).objectFit(ImageFit.Fill)...})}.autoPlay(true).displayCount(this.swiperDisplayCount.getValue(this.breakpointModel.currentBreakpoint))}}}

Banner 的设计特点:

  • 通过@Param bannerArray接收图片数组,不同页面可以传入不同的图片
  • 内置断点响应式,自动根据屏幕宽度调整显示数量(sm: 1, md: 2, lg: 3)
  • @Param提供默认值,空数组也能正常渲染

五、组件接口的兼容性设计

通用组件在跨模块复用时,接口设计需要兼顾灵活性和简洁性:

@Param 的默认值

提供合理的默认值,使调用方可以用最少的参数使用组件:

@Paramtitle:string|Resource='';// 默认为空@ParamonClickBack:()=>void=()=>{};// 默认无操作@ParambgColor:ResourceStr=$r('sys.color.background_secondary');// 默认背景

单向数据流

所有输入通过@Param传入,组件内部使用@Local管理内部状态。这种单向数据流的设计保证了组件行为的可预测性。

事件回调

通过回调函数(如onClickBack)而不是直接调用RouterModule.pop(),组件的导航行为由调用方决定,通用性更强。

六、跨模块引用的实现机制

在 11 模块架构中,跨模块引用的实现依赖于:

  1. Index.ets:commonLib 的Index.ets导出所有公共组件、模型、工具类
// commons/commonLib/Index.etsexport{TopBar}from'./src/main/ets/components/TopBar';export{Banner}from'./src/main/ets/components/Banner';export{CommonHeader}from'./src/main/ets/components/CommonHeader';export{RouterMap}from'./src/main/ets/constants/RouterMap';export{AudioPlayer}from'./src/main/ets/utils/AudioPlayer';// ...
  1. oh-package.json5:在 feature 模块的依赖中声明 commonLib
// features/homePage/oh-package.json5 { "dependencies": { "commonlib": "file:../../commons/commonLib" } }
  1. import 引用:在具体页面中通过模块名引用
import{TopBar,Banner,RouterMap,RouterModule}from'commonlib';

七、总结

组件复用是 11 模块架构的核心设计原则之一。TopBar、CommonHeader、Banner 三个通用组件在 homePage、minePage、topicPage 等多个模块中实现了跨模块复用,避免了重复编码。通过@Param提供灵活的参数接口和合理的默认值、通过回调函数解耦导航逻辑、通过 Index.ets 统一导出,commonLib 中的通用组件真正做到了"一次编写,多处运行"。在实际开发中,判断一个组件是否应该放入 commonLib 的标准是:是否被两个或以上不同模块引用。满足这个条件的组件,就应该考虑提取为通用组件。