当前位置: 首页 > news >正文

HarmonyOS开发实战:笔友-CommonComponents 组件库设计哲学——聚合与拆分的权衡

前言

在 ArkUI 声明式开发范式中,组件复用是提升开发效率和 UI 一致性的关键手段。xiexin 将 5 个通用组件集中放在一个 146 行的CommonComponents.ets文件中,这种"单文件聚合"的设计在小型项目中极具性价比,但随着项目规模增长,需要向"多文件拆分"演进。

本文将以CommonComponents.ets为蓝本,详细剖析组件库设计中的"聚合 vs 拆分"选择、组件的导出/引用机制、@Component/@Prop/@BuilderParam在组件封装中的配合,以及组件库随着项目规模增长的演进路线。

一、CommonComponents 的整体设计

1.1 文件结构

xiexin 的CommonComponents.ets位于:

entry/src/main/ets/components/CommonComponents.ets

整个文件 146 行,包含 5 个组件:

组件行数装饰器用途
AvatarComponent34@Component@Prop头像显示,首字母回退
StatusBadge22@Component@Prop信件/笔友状态标签
CardContainer19@Component@BuilderParam通用卡片容器
EmptyState49@Component@Prop空状态占位
DividerLine10@Component@Prop分割线

1.2 所有组件代码

// entry/src/main/ets/components/CommonComponents.etsimport{AppColors}from'../common/Constants';// 通用头像组件@Componentexportstruct AvatarComponent{@Propname:string='';@PropavatarSize:number=48;@PropfontSize:number=18;privategetAvatarColor():string{constcolors:string[]=['#E8D5B7','#D4C4A8','#C9B896','#BFA98A','#D1C0A5','#C2B59B'];lethash:number=0;for(leti=0;i<this.name.length;i++){hash=this.name.charCodeAt(i)+((hash<<5)-hash);}returncolors[Math.abs(hash)%colors.length];}build(){Stack(){Circle().width(this.avatarSize).height(this.avatarSize).fill(this.getAvatarColor())Text(this.name.length>0?this.name.charAt(0):'?').fontSize(this.fontSize).fontColor(AppColors.TEXT_PRIMARY).fontWeight(FontWeight.Medium)}.width(this.avatarSize).height(this.avatarSize)}}// 状态标签组件@Componentexportstruct StatusBadge{@Proptext:string='';@Propcolor:string=AppColors.PRIMARY;@PropbgColor:string=AppColors.AMBER_LIGHT;build(){Text(this.text).fontSize(11).fontColor(this.color).backgroundColor(this.bgColor).borderRadius(10).padding({left:8,right:8,top:3,bottom:3}).fontWeight(FontWeight.Medium)}}// 通用卡片容器@Componentexportstruct CardContainer{@BuilderParamcontent:()=>void;@PropcardPadding:number=16;build(){Column(){this.content()}.width('100%').padding(this.cardPadding).backgroundColor(AppColors.CARD_BG).borderRadius(16).shadow({radius:8,color:'#0D000000',offsetX:0,offsetY:2})}}// 空状态组件@Componentexportstruct EmptyState{@Proptitle:string='暂无内容';@Propsubtitle:string='';@PropshowButton:boolean=false;@PropbuttonText:string='';onButtonClick?:()=>void;build(){Column({space:16}){Column(){Text('🏔').fontSize(64).opacity(0.3)}.margin({top:60})Text(this.title).fontSize(16).fontColor(AppColors.TEXT_SECONDARY)if(this.subtitle.length>0){Text(this.subtitle).fontSize(13).fontColor(AppColors.TEXT_SECONDARY).opacity(0.7)}if(this.showButton){Button(this.buttonText).fontSize(14).fontColor(AppColors.WHITE).backgroundColor(AppColors.PRIMARY).borderRadius(24).height(40).width(140).margin({top:16}).onClick(()=>{if(this.onButtonClick){this.onButtonClick();}})}}.width('100%').justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)}}// 分割线组件@Componentexportstruct DividerLine{@PropmarginH:number=16;build(){Divider().strokeWidth(0.5).color(AppColors.DIVIDER).margin({left:this.marginH,right:this.marginH})}}

二、单文件聚合 vs 多文件拆分

2.1 两种模式的对比

维度单文件聚合(xiexin 当前)多文件拆分
文件数量1 个N 个
代码定位在同一文件中滚动在目录中查找文件名
组件耦合可见,便于发现耦合隐藏,独立文件
导入语句一次 import 全部每个组件独立 import
适合阶段小型项目(< 10 组件)中大型项目(> 10 组件)

2.2 导入方式的差异

// 单文件聚合:一次 import 全部import{AvatarComponent,StatusBadge,CardContainer,EmptyState,DividerLine}from'../components/CommonComponents';// 多文件拆分:每个组件独立 importimport{AvatarComponent}from'../components/AvatarComponent';import{StatusBadge}from'../components/StatusBadge';

2.3 组件库目录结构演进

// 小型项目:单文件 components/CommonComponents.ets // 中型项目:按类别拆分 components/ ├── AvatarComponent.ets ├── StatusBadge.ets ├── CardContainer.ets ├── EmptyState.ets └── DividerLine.ets // 大型项目:按模块分组 components/ ├── avatars/ │ ├── AvatarComponent.ets │ └── GroupAvatar.ets ├── badges/ │ ├── StatusBadge.ets │ └── CountBadge.ets ├── cards/ │ ├── CardContainer.ets │ └── StatsCard.ets └── states/ └── EmptyState.ets

三、@Component 的导出与引用

3.1 export struct 的语义

@Componentexportstruct AvatarComponent{@Propname:string='';@PropavatarSize:number=48;@PropfontSize:number=18;}

3.2 在页面中引用

import{AvatarComponent,StatusBadge,EmptyState}from'../components/CommonComponents';@BuilderLetterCard(letter:Letter){Row(){AvatarComponent({name:letter.penPalName,avatarSize:40,fontSize:16})Column({space:6}){Text(letter.penPalName).fontSize(16)StatusBadge({text:this.getStatusText(letter),color:AppColors.PRIMARY})}}}

四、@BuilderParam 插槽设计

4.1 CardContainer 的插槽

@Componentexportstruct CardContainer{@BuilderParamcontent:()=>void;@PropcardPadding:number=16;build(){Column(){this.content()}.width('100%').padding(this.cardPadding).backgroundColor(AppColors.CARD_BG).borderRadius(16).shadow({radius:8,color:'#0D000000',offsetX:0,offsetY:2})}}

五、计算属性在组件中的使用

privategetAvatarColor():string{constcolors:string[]=['#E8D5B7','#D4C4A8','#C9B896','#BFA98A','#D1C0A5','#C2B59B'];lethash:number=0;for(leti=0;i<this.name.length;i++){hash=this.name.charCodeAt(i)+((hash<<5)-hash);}returncolors[Math.abs(hash)%colors.length];}

六、条件渲染在组件中的应用

if(this.subtitle.length>0){Text(this.subtitle)}if(this.showButton){Button(this.buttonText)}

七、组件参数设计原则

// 好的参数设计:明确的默认值@Propname:string='';@PropavatarSize:number=48;@PropfontSize:number=18;// 可选回调函数onButtonClick?:()=>void;

八、组件库的测试策略

import{describe,it,expect}from'@ohos/hypium';describe('EmptyState',()=>{it('should display title when provided',()=>{constcomponent=newEmptyState();component.title='测试标题';expect(component.title).toBe('测试标题');});});

九、组件的扩展建议

@Componentexportstruct AvatarComponent{@Propname:string='';@PropavatarUrl:string='';@PropavatarSize:number=48;@PropfontSize:number=18;build(){Stack(){if(this.avatarUrl.length>0){Image(this.avatarUrl).width(this.avatarSize).height(this.avatarSize).borderRadius(this.avatarSize/2)}else{Circle().width(this.avatarSize).height(this.avatarSize).fill(this.getAvatarColor())Text(this.name.charAt(0)).fontSize(this.fontSize).fontColor(AppColors.TEXT_PRIMARY)}}.width(this.avatarSize).height(this.avatarSize)}}

九、组件库的版本管理策略

当组件库需要版本迭代时,推荐以下策略:

  1. 新增组件:在 CommonComponents 文件中新增组件,不影响现有组件
  2. 修改组件:修改@Prop参数时,考虑向后兼容性
  3. 废弃组件:保留旧接口,添加@deprecated注释
/** * @deprecated 请使用 NewAvatarComponent 替代 */@Componentexportstruct AvatarComponent{// 旧接口}

十、组件库的文档化

组件库的文档化是团队协作的关键:

  • 每个组件需要标注@Prop参数说明
  • 提供使用示例代码
  • 标注不兼容的变更
/** * 头像组件 * @param name 用户名,用于首字母和颜色计算 * @param avatarSize 头像尺寸(默认 48) * @param fontSize 首字母字号(默认 18) */@Componentexportstruct AvatarComponent{@Propname:string='';@PropavatarSize:number=48;@PropfontSize:number=18;}

十一、从 xiexin 看组件库设计

xiexin 的组件库设计体现了"够用就好"的原则:

  1. 单文件聚合:5 个组件,146 行,适合当前阶段
  2. @Prop 参数化:所有组件可通过参数定制
  3. @BuilderParam 插槽:CardContainer 支持内容注入
  4. 可选回调:EmptyState 的 onButtonClick 可选

提示:当组件数量超过 10 个时,建议按"组件类型"拆分到独立文件,避免单文件膨胀。

十二、组件库的 CI/CD 集成

在团队协作中,组件库的自动化测试和发布是保证质量的关键:

  1. 单元测试:每个组件需要有对应的@ohos/hypium测试用例
  2. 视觉回归测试:使用截图对比工具检测 UI 变化
  3. 自动发布:组件库可以发布为 HAR 包,供其他模块使用
// oh-package.json5 { "dependencies": { "@xiexin/common-components": "1.0.0" } }

总结

本文详细剖析了 xiexin 的 CommonComponents 组件库设计哲学,重点讲解了单文件聚合 vs 多文件拆分的权衡、@Prop 参数化设计、@BuilderParam 插槽模式,以及组件库随着项目规模增长的演进路线。

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!


相关资源:

  • 开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
  • HarmonyOS 应用开发指南:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/application-dev-guide
  • HarmonyOS 状态管理概述:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-state-management-overview
  • HarmonyOS 高性能编程实践:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-high-performance-programming
  • HarmonyOS 组件复用:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-component-reusable
  • HarmonyOS 自定义组件:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-custom-components
  • HarmonyOS 组件封装:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-component-encapsulation
  • HarmonyOS @Builder 装饰器:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-builder
  • HarmonyOS @BuilderParam 装饰器:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-builderparam
  • HarmonyOS 自定义组件:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-custom-components
  • HarmonyOS 组件封装:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-component-encapsulation
  • HarmonyOS @Builder 装饰器:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-builder
  • HarmonyOS @BuilderParam 装饰器:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-builderparam
  • HarmonyOS @Prop 装饰器:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-prop
  • HarmonyOS 组件复用开发实践:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-component_reuse
  • HarmonyOS 状态管理概述:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-state-management-overview
  • HarmonyOS 自定义组件生命周期:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-custom-components-lifecycle
http://www.jsqmd.com/news/1261791/

相关文章:

  • 2026 遵义汇川漏水检测维修必须推荐全区域覆盖 - 超人防水
  • Python三大神器项目落地指南:迭代器、生成器、装饰器真实业务应用大全
  • MCAN模块架构与CAN FD协议深度解析:从原理到工程实践
  • 2026安徽新华高级技工学校终身包就业是真的吗? - 小张zc
  • WSL环境下Autoware图形界面问题排查与优化
  • Python与Unity结合实现动态水流模拟:从波动方程到实时渲染
  • 语言模型在分子空间约束生成中的能力与局限
  • 宜昌市政建材采购怎么选?一站式还是多头对接,看清供应链闭环才不踩坑 - 中国品牌企业推荐网
  • AMD掌门人苏姿丰年轻时的照片
  • 宠物用品推荐系统
  • Ohook:终极Office激活解决方案 - 永久免费解锁Microsoft 365完整功能
  • 构建可控AI Agent:领域知识库与动态规则引擎实践
  • 全职直播三年实测|老实说,很多主播赚不到钱真的不是能力问题 - 彭拜新闻(测评)
  • 在Node.js后端服务中集成多模型API以应对不同场景需求
  • 文创作品线上大众评选,微信投票实操教程 - 微信投票小程序
  • 中包机PLC数据采集物联网解决方案
  • 2026 年 7 月新发布:江海评价高的双碳馆设计制造厂选哪家,别再盲目建设!这套设计颠覆了你的认知 - 行业推荐官[官方】--
  • ONNX运行时优化生成式AI模型部署实践
  • 3大核心技术破解大众点评反爬:Python爬虫实战指南
  • 嵌入式AES硬件加速器GCM/CCM模式实战:从原理到寄存器配置
  • 高校毕业生实习管理系统
  • Windows 11系统优化终极指南:一键清理垃圾提升性能51%
  • Unity AssetBundle热更新实战:资源划分、版本管理与内存优化
  • Claude Agent SDK开发指南:构建智能对话系统实战
  • C++右值引用与移动语义:从概念到实战的性能优化指南
  • kv存储主从复制的设计与实现
  • eBPF 与 bpftrace:更深入地观测内核
  • 基于3D ResNet的平扫CT智能诊断系统设计与优化
  • 如何在普通PC上安装macOS:OpenCore黑苹果完整实战指南
  • 紧急更新!iOS/Android底层API变更导致73%番茄AI应用失效,附3行代码热修复方案与兼容性迁移清单(限时48小时)