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

一、组件复用的价值
在 11 模块架构中,组件复用是减少代码重复、保持 UI 一致性的关键策略。通过将通用 UI 组件提取到 commonLib 模块,所有 feature 和 component 模块都可以共享这些组件,而无需在每个模块中重复实现。
组件复用的主要收益:
- 开发效率提升:一次实现,多处使用,减少重复编码
- UI 一致性:所有页面使用相同的 TopBar、CommonHeader,视觉风格统一
- 维护成本降低:组件修改只在 commonLib 中进行,所有引用自动更新
- Bug 减少:经过多模块验证的组件,质量更有保障
二、TopBar 组件的跨模块复用
TopBar 是最基础的复用组件,位于 commons/commonLib/src/main/ets/components/TopBar.ets:
@ComponentV2
export struct TopBar {
@Param title: string | Resource = '';
@Param onClickBack: () => 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)是另一种结构的头部组件,提供了更多的功能选项:
@ComponentV2
export struct TopTabsBuilder {
@Param title: string = '';
@Param bgColor: ResourceStr = $r('sys.color.background_secondary');
@Param showBackButton: boolean = false;
@Param type: string = '一级建造师';
@Local index: number = 0;
}
// 使用示例
TopTabsBuilder({
title: '我的课程',
showBackButton: true,
type: '英语学习'
})
CommonHeader 比 TopBar 更复杂,支持:
- 搜索按钮
- 下拉选择
- 自定义背景色
- 可选的返回按钮
四、Banner 组件的复用
Banner 轮播图组件同样位于 commonLib:
@ComponentV2
export struct Banner {
@Param bannerArray: Array<ResourceStr> = [
$r('app.media.banner1'),
];
@Local breakpointModel: BreakpointModel = AppStorageV2.connect(BreakpointModel, ...)!;
swiperDisplayCount: BreakpointType<number> = new BreakpointType<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 的默认值
提供合理的默认值,使调用方可以用最少的参数使用组件:
@Param title: string | Resource = ''; // 默认为空
@Param onClickBack: () => void = () => {}; // 默认无操作
@Param bgColor: ResourceStr = $r('sys.color.background_secondary'); // 默认背景
单向数据流
所有输入通过 @Param 传入,组件内部使用 @Local 管理内部状态。这种单向数据流的设计保证了组件行为的可预测性。
事件回调
通过回调函数(如 onClickBack)而不是直接调用 RouterModule.pop(),组件的导航行为由调用方决定,通用性更强。
六、跨模块引用的实现机制
在 11 模块架构中,跨模块引用的实现依赖于:
- Index.ets:commonLib 的
Index.ets导出所有公共组件、模型、工具类
// commons/commonLib/Index.ets
export { 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';
// ...
- oh-package.json5:在 feature 模块的依赖中声明 commonLib
// features/homePage/oh-package.json5
{
"dependencies": {
"commonlib": "file:../../commons/commonLib"
}
}
- import 引用:在具体页面中通过模块名引用
import { TopBar, Banner, RouterMap, RouterModule } from 'commonlib';
七、总结
组件复用是 11 模块架构的核心设计原则之一。TopBar、CommonHeader、Banner 三个通用组件在 homePage、minePage、topicPage 等多个模块中实现了跨模块复用,避免了重复编码。通过 @Param 提供灵活的参数接口和合理的默认值、通过回调函数解耦导航逻辑、通过 Index.ets 统一导出,commonLib 中的通用组件真正做到了"一次编写,多处运行"。在实际开发中,判断一个组件是否应该放入 commonLib 的标准是:是否被两个或以上不同模块引用。满足这个条件的组件,就应该考虑提取为通用组件。
更多推荐



所有评论(0)