@Builder 与 @BuilderParam — 鸿蒙 UI 复用最佳实践

在这里插入图片描述

概述

在鸿蒙 ArkTS 开发中,UI 复用是提升开发效率和保持界面一致性的关键。面对复杂的业务页面,如果没有有效的复用机制,build() 方法会迅速膨胀到数百行的规模,充斥着大量重复的布局代码。更棘手的是跨场景复用问题——同一个基础容器组件在不同的业务模块中可能需要完全不同的内部内容。ArkTS 提供了 @Builder@BuilderParam 两种装饰器来解决这一挑战:@Builder 用于定义可复用的 UI 构建函数,将一段 UI 结构封装为函数;@BuilderParam 则允许父组件向子组件注入自定义的 UI 片段,实现类似 Web 框架中"插槽"(slot)的模式。MoneyTrack 项目广泛使用这两种装饰器来构建灵活、可组合的 UI 组件体系。

核心知识点

1. 内联 @Builder 的定义与使用

@Builder 装饰器可用于组件内部,定义仅在该组件内使用的 UI 构建函数。MoneyTrack 中的 StatisticsView 使用内联 @Builder 将复杂的 UI 拆分为多个独立的构建方法:

@ComponentV2
export struct StatisticsView {
  @Builder
  filterBarBuilder() {
    Row() {
      // 月份选择器、成员选择器、视图切换、分享按钮
    }
  }

  @Builder
  monthSheetBuilder() {
    CommonMonthPicker({ ... });
  }

  @Builder
  memberSheetBuilder() {
    Column() {
      Text('选择成员')
      List() { ... }
    }
  }
}

每个 @Builder 方法管理一个独立的 UI 区域,使得 build() 方法的结构清晰易懂,各区域逻辑互不干扰。

2. @Builder 的有参形式

@Builder 可以接受参数,实现参数化的 UI 构建。以下是 MemberPrivacy 中的带参构建器示例:

@Builder
export function MemberPrivacy(content: string) {
  Scroll() {
    Text(content).fontSize(14).lineHeight(20);
  }.height('100%').align(Alignment.Top).padding(16).scrollBar(BarState.Off);
}

参数化 @Builder 使得同一段 UI 逻辑可以根据传入参数渲染不同的内容,减少了重复的模板代码。参数类型可以是基础类型、对象、甚至是回调函数。

3. @BuilderParam 的插槽模式

@BuilderParam 是 ArkTS 实现组件间 UI 注入的核心机制。它允许父组件将一段 UI 构建逻辑传入子组件,由子组件在合适的位置渲染。下图展示了这种模式的数据流:

子组件

父组件

定义 @Builder
customContent()

传入子组件
contentBuilder: customContent

@BuilderParam
contentBuilder

在 build() 中调用
this.contentBuilder()

渲染注入的 UI 内容

MoneyTrack 中的 ContainerRow 组件是这一模式的典型应用:

@ComponentV2
export struct ContainerRow {
  @BuilderParam customBuilderParam: () => void;

  build() {
    Row() {
      this.customBuilderParam();
    }
    .width($r('app.string.width_percent_full'))
    .alignItems(VerticalAlign.Center)
    .borderRadius($r('app.string.border_radius_16'))
    .padding($r('app.string.space_m'));
  }
}

父组件使用时只需传入自定义构建器:

ContainerRow({ customBuilderParam: this.myContentBuilder })

这种模式使 ContainerRow 成为了一个"带样式的容器",内部内容完全由父组件控制,实现了容器样式与内容的完美解耦。

4. 全局 @Builder 跨模块复用

通过 export 关键字,@Builder 可以被导出为全局函数,供其他模块甚至跨 HAR 包引用。这在 router_map.json 的页面路由注册场景中尤为重要:

{
  "name": "BillDetailPage",
  "pageSourceFile": "src/main/ets/views/BillDetailPage.ets",
  "buildFunction": "billDetailPageBuilder"
}

对应的全局构建器定义如下:

// BillDetailPage.ets
@Builder
export function billDetailPageBuilder() {
  BillDetailPage();
}

在 MoneyTrack 中,homeassetsstatisticsmine 等各特性模块的 router_map.json 都使用 buildFunction 字段引用 @Builder 导出的全局函数。这种跨模块的构建器导出机制,是实现基于 NavDestination 的路由导航体系的基础。

5. @Builder 与自定义组件的选择

@Builder 和自定义组件(@ComponentV2)都可以封装 UI,但适用场景不同:

  • 使用 @Builder 当:UI 结构简单、无独立状态管理需求、仅作为较大组件的一部分。
  • 使用自定义组件当:UI 区域需要独立的状态管理、生命周期钩子、或需要被多个页面单独复用。

一个经验法则:如果一段 UI 需要自己的 @Local@Param,就应该提取为独立组件;否则,用 @Builder 足够了

项目案例

d:\HarmonyOS\WorkSpace\MoneyTrack1.0.3\features\statistics\src\main\ets\views\StatisticsView.etsfilterBarBuilder() 是内联 @Builder 的典型使用。d:\HarmonyOS\WorkSpace\MoneyTrack1.0.3\components\feedback\src\main\ets\FeedbackTrigger.ets@BuilderParam contentBuilder 展示了外部注入 UI 的模式。d:\HarmonyOS\WorkSpace\MoneyTrack1.0.3\commons\commonlib\src\main\ets\components\ContainerRow.ets 中的 @BuilderParam customBuilderParam 实现了容器样式与内容的解耦。

总结

@Builder@BuilderParam 是 ArkTS 中实现 UI 复用的两大利器。@Builder 解决了"相同 UI 逻辑多处调用"的问题,支持无参和有参两种形式,还能通过 export 实现跨模块导出;@BuilderParam 更进一步,解决了"相同容器不同内容"的问题,通过插槽模式让父组件控制子组件的内部渲染内容。在 MoneyTrack 中,从页面内的区域拆分,到跨模块的页面路由注册,再到通用容器的内容注入,@Builder@BuilderParam 贯穿了整个 UI 层,是构建模块化、可组合应用的基石。最佳实践是:用 @Builder 拆分页面内的 UI 区域,用 @BuilderParam 设计高度灵活的可注入容器组件,用全局 @Builder 实现页面路由和跨 HAR 的 UI 共享。

参考文档

  • @Builder 装饰器指南
  • @BuilderParam 装饰器指南
  • 组件化 UI 构建与复用最佳实践
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐