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

HarmonyOS掌上记账APP开发实践第28篇:自定义组件封装策略 — 从通用 Header 到业务组件的分层设计

自定义组件封装策略 — 从通用 Header 到业务组件的分层设计

一、引言

在大型应用中,合理的组件化设计是保证代码可维护性和复用性的基石。鸿蒙的 ArkTS 通过@ComponentV2装饰器支持自定义组件,允许开发者将页面拆分为可复用的独立模块。MoneyTrack 项目从通用基础组件(如 CommonHeader)到业务领域组件(如 AssetSummaryCard、AssetCard),构建了一套清晰的组件分层体系,实现了代码的高复用和低耦合。

二、核心知识点

2.1 @ComponentV2 与 @Component(V1) 对比

鸿蒙 ArkTS 提供了两代组件装饰器。@ComponentV2(推荐)相较于@Component(V1)在响应式和性能上有显著提升:

对比维度@ComponentV2@Component(V1)
数据装饰器@Param / @Local / @Computed@State / @Prop / @Link
响应式粒度属性级,精准触发更新对象引用级,整体替换才触发
性能表现仅更新变动的属性整个组件重建
语法简洁度不需要 .build() 内部赋初值略繁琐
推荐程度强烈推荐(新项目应使用)兼容旧项目
// @ComponentV2 写法(推荐)@ComponentV2exportstruct MyComponent{@Paramcount:number=0@LocalisVisible:boolean=truebuild(){/* ... */}}// @Component(V1) 写法(旧)@Componentexportstruct OldComponent{@Statecount:number=0@PropisVisible:boolean=truebuild(){/* ... */}}

2.2 @Param 与 @Local 的角色分配

@ComponentV2中,数据装饰器的选择决定了属性的职责:

  • @Param:接收父组件传入的外部属性(即 props),由父组件驱动更新。子组件不应修改@Param属性。
  • @Local:组件内部管理的私有状态,仅供组件自身使用,外界不可直接赋值。
@ComponentV2exportstruct UserCard{@ParamuserName:string=''// 父组件传入,只读@ParamavatarUrl:string=''// 父组件传入,只读@LocalisExpanded:boolean=false// 组件内部状态@LocallikeCount:number=0// 组件内部状态build(){Column(){Text(this.userName).fontSize(16)if(this.isExpanded){Text('详细资料...')}}}}

分配原则:凡是从父组件传入的数据用@Param,组件自己管理的交互状态用@Local

2.3 组件通信方式

自定义组件之间通过单向数据流进行通信:

  • 父→子:通过@Param属性传递数据
  • 子→父:通过回调函数(事件)通知父组件
// 父组件使用@ComponentV2exportstruct ParentPage{@Localitems:number[]=[1,2,3]build(){Column(){ForEach(this.items,(item:number)=>{ChildCard({value:item,onDelete:(id:number)=>{this.items=this.items.filter(v=>v!==id)}})})}}}// 子组件定义@ComponentV2exportstruct ChildCard{@Paramvalue:number=0@ParamonDelete:(id:number)=>void=()=>{}build(){Row(){Text(`${this.value}`)Button('删除').onClick(()=>this.onDelete(this.value))}}}

这种模式确保了数据从父到子单向流动,子组件通过回调通知父组件执行修改,避免了双向绑定的混乱。

2.4 组件封装的最佳粒度

组件拆分需要遵循"高内聚、低耦合"原则。MoneyTrack 的组件分为三个层次:

App(应用根节点)

TabBar(底部导航)

BillPage(账单页)

StatisticsPage(统计页)

MinePage(我的页)

CommonHeader(通用标题栏)

DailyBillGroup(每日分组)

BillCard(账单卡片)

CategoryIcon(分类图标)

ChartSummary(图表摘要)

CalendarSummary(日历摘要)

MemberCard(会员卡片)

SettingItem(设置项)

经验法则

  1. 单一职责:一个组件只做一件事。BillCard只负责展示单条账单,不负责布局列表。
  2. 接口归一化:组件的@Param应设计为统一的 Model 类型,而非零散的基础类型。
  3. props 不可变性:子组件应只读地消费@Param,不直接修改父组件数据。

2.5 CommonHeader 完整实现

以下是 MoneyTrack 中 CommonHeader 的完整代码:

@ComponentV2exportstruct CommonHeader{@Paramtitle:string=''@ParamonBack:()=>void=()=>{}@ParamrightText:string=''@ParamonRightClick:()=>void=()=>{}@ParamisDarkMode:boolean=falsebuild(){Row(){// 左侧返回按钮Image($r('app.media.ic_back')).width(24).height(24).onClick(()=>this.onBack())// 中间标题Text(this.title).fontSize(18).fontWeight(FontWeight.Bold).fontColor(this.isDarkMode?'#FFFFFF':'#333333')Blank()// 右侧可选操作if(this.rightText.length>0){Text(this.rightText).fontSize(14).fontColor('#007AFF').onClick(()=>this.onRightClick())}}.padding({left:16,right:16,top:12,bottom:12}).width('100%').backgroundColor(this.isDarkMode?'#1A1A1A':'#FFFFFF')}}

三、项目代码案例

3.1 CommonHeader 通用标题栏

products/entry/src/main/ets/components/CommonHeader.ets中,CommonHeader 封装了统一的导航栏。该组件在 BillDetailPage、AssetDetailPage、SettingPage 等多个页面中复用,保证了导航栏的视觉统一。

3.2 AssetSummaryCard / AssetCard 业务卡片

在资产模块中,业务卡片组件封装了资产数据展示的公共逻辑:

  • AssetSummaryCard:展示资产总览摘要(总资产、净资产等汇总指标)
  • AssetCard:展示单个资产项目名称、金额、账期信息

这些组件通过@Param接收AssetGroupModelAssetItemModel数据对象,渲染出统一的卡片 UI。

3.3 组件定义示例

@ComponentV2exportstruct AssetCard{@ParamassetData:AssetGroupModel=newAssetGroupModel()@ParamonTap:(id:number)=>void=()=>{}build(){Column(){Text(this.assetData.name).fontSize(16).fontWeight(FontWeight.Bold)Text(`¥${this.assetData.amount.toFixed(2)}`).fontSize(24)}.gesture(TapGesture().onAction(()=>{this.onTap(this.assetData.id)})).padding(16).backgroundColor(Color.White).borderRadius(12)}}

四、最佳实践总结

  1. 优先使用 @ComponentV2:新一代装饰器性能更好、语法更简洁。
  2. @Param 与 @Local 职责分明:外部数据用@Param,内部状态用@Local
  3. 单向数据流:父传子通过 props,子传父通过回调。
  4. 组件粒度适中:过细则文件碎片化,过粗则不可复用。
  5. 保持 props 不可变:子组件不修改传入的数据,确保数据流可预测。
  6. 接口归一化:推荐传入完整 Model 对象,而非零散字段。

五、参考文档

  • 自定义组件最佳实践
  • @ComponentV2 装饰器说明
  • @Param 装饰器
http://www.cnnetsun.cn/news/3463914.html

相关文章:

  • 设备巡检报修系统小程序开发
  • JavaScript项目测试实战:从单元测试到集成测试的完整指南
  • 【关注可白嫖源码】--课程设计--毕业设计--springboot二次元周边售卖网站[编号:project18448](案件分析)
  • 家里的总电闸要拉一拉就知道——配置中心不是把参数挪个地方,是让你改一个值全屋都不用动
  • MC3172 RISC-V开发板环境搭建与多线程编程实战
  • TVA:具身智能技术生态的强力引擎(9)
  • Java基础中级进阶篇六之网络编程(反射、网络编程)
  • 【Gemini会议助手深度解析】:20年AI产品经理亲测的5大隐藏功能,90%用户从未用过!
  • AI创业中的知识产权策略:模型版权、数据授权与开源合规的避坑指南
  • 具身智能的定义、特征与原理解析(17)
  • 游戏数据看板需要哪些指标:核心逻辑、执行步骤与关键指标
  • 如何解决AI到word的格式问题?用 AI 导出鸭终结排版崩坏噩梦
  • DDE-GoCode与其他桌面环境依赖包的终极对比分析:为什么选择正确的依赖包至关重要
  • FPGA开发板按键与LED控制实战:从消抖到状态机
  • AI Agent技能架构与工程实践全解析
  • Unveiling Intrinsic Text Bias in Multimodal Large Language Models through Attention Key-Space Ana...
  • opendesign-deployment项目架构详解:构建稳定可靠的设计系统部署方案
  • Mac版Office 365 16.80 Universal深度解析与优化指南
  • CH57x蓝牙5.0开发实战:从机/主机模式与性能优化
  • 本地锁与分布式锁:Java本地锁为什么扛不住集群?
  • KiCad中高效使用AD封装库的完整指南
  • 5步掌握IINA:打造macOS专业级视频播放体验的完整指南
  • Claude与Codex协同开发:AI架构师与程序员组合实践
  • Codex 是 Agent 时代的操作系统底板:MCP 协议与 Skills 运行时解析
  • 智能Agent开发指南:从架构设计到实战应用
  • 计算机毕业设计之jsp智慧社区服务中心信息管理系统
  • MCU 上电启动流程
  • 昆明性价比装修哪家好?2026昆明高性价比整装公司排名
  • 代码生成这块骨头,智谱是怎么啃的
  • 原料药企业切入具身智能,科源制药当前估值蕴含多少新业务预期