在 HarmonyOS (ArkTS) 开发中,@Builder 是一个极其强大的装饰器,它允许开发者将重复使用的 UI 结构封装成自定义函数。这不仅极大地提升了代码的复用性,还让组件树的结构更加清晰、易于维护。

以下是对 @Builder 的深度解析。


1. 核心概念:什么是 @Builder

@Builder 用于装饰类内部的方法。被装饰的方法不再是一个普通的 JavaScript/TypeScript 函数,而是一个构建函数

  • 作用:描述一段 UI 结构(组件树)。
  • 调用方式:必须在组件的 build() 方法或其他 @Builder 方法中,通过 this.方法名() 调用。
  • 优势
    • 代码复用:避免相同的 UI 代码在多处复制粘贴。
    • 逻辑解耦:将复杂的 UI 布局抽离,使主 build() 方法更专注于整体页面结构。
    • 参数化渲染:支持传入参数,动态生成不同内容的相同结构组件。

基本语法结构

@Entry
@Component
struct MyComponent {
  // 1. 定义 @Builder 函数
  @Builder
  myCustomView(param1: string, param2: number) {
    // 这里编写具体的 UI 结构
    Row() {
      Text(param1)
      Text(`${param2}`)
    }
  }

  // 2. 在 build 中调用
  build() {
    Column() {
      // 通过 this 调用
      this.myCustomView('Hello', 100)
      this.myCustomView('World', 200)
    }
  }
}

2. 示例代码

展示了如何使用 @Builder 创建一个通用的标题栏。

完整代码

@Entry
@Component
struct Index {
  // 定义数据源,模拟实际开发场景
  private titles: string[] = ['每日推荐', '推荐歌单', '私人漫游', '最新音乐'];

  /**
   * 自定义构建函数:通用标题栏
   * @param title 标题文本
   * @param onClick 可选的点击回调
   */
  @Builder
  titleBuilder(title: string, onClick?: () => void) {
    Row() {
      Text(title)
        .fontSize(18)           // 增加字号,提升可读性
        .fontWeight(FontWeight.Medium) // 使用枚举定义字重,比数字更语义化
        .fontColor('#ffffff')
        .layoutWeight(1)        // 占满剩余空间
      
      // 示例:添加一个右侧箭头图标,增强交互感
      Image($r('sys.media.ohos_ic_public_arrow_right')) 
        .width(16)
        .height(16)
        .fillColor('#cccccc')
        .margin({ right: 5 })
    }
    .width('100%')
    .height(56)                 // 稍微增加高度,符合现代设计规范
    .justifyContent(FlexAlign.SpaceBetween) // 两端对齐
    .onClick(() => {
      if (onClick) {
        onClick();
      } else {
        console.info(`Clicked on title: ${title}`);
      }
    })
    .hoverEffect(true)          // 开启点击态水波纹效果 (API 9+)
  }

  build() {
    Column() {
      // 顶部导航栏示例
      Text('音乐首页')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
        .fontColor('#fff')
        .margin({ bottom: 20, top: 10 })

      // 循环渲染列表,展示 @Builder 的复用能力
      ForEach(this.titles, (item: string) => {
        this.titleBuilder(item, () => {
          // 处理具体点击逻辑
          console.log(`Navigating to: ${item}`);
          // alert(`进入 ${item} 页面`); 
        })
        .margin({ bottom: 10 }) // 给每个条目增加间距
      }, (item: string) => item) // 唯一键生成函数
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#131313')
    .padding({ left: 16, right: 16, top: 10 })
  }
}

3. @Builder 的高级用法与注意事项

3.1 参数传递策略

@Builder 函数可以接收任意类型的参数,包括:

  • 基础类型string, number, boolean
  • 对象类型:传递配置对象,减少参数个数。
  • 函数类型:如示例中的 onClick,实现逻辑与视图的分离。
@Builder
configCard(config: { title: string, color: string, icon: Resource }) {
  // 使用 config 对象解构
  const { title, color, icon } = config;
  // ... UI 构建
}

3.2 状态响应性

重要提示@Builder 函数本身不会自动创建新的组件实例来响应状态变化,它依赖于调用它的上下文。

  • 如果 @Builder 内部使用了 @State@Prop 装饰的变量,当这些变量变化时,整个包含该 @Builder 调用的父组件会刷新(除非配合 LazyForEach 或其他优化手段)。
  • 若需精细控制刷新,建议在 @Builder 内部直接使用状态变量,ArkUI 框架会自动追踪依赖。

3.3 与 @Styles 的区别

很多初学者容易混淆 @Builder@Styles

特性 @Builder @Styles
定义内容 UI 结构 + 样式 (可以包含 Row, Column, Text 等组件) 仅样式 (只能包含属性设置,如 width, color)
复用粒度 粗粒度 (复用整个模块/卡片) 细粒度 (复用一套样式配置)
参数支持 支持复杂逻辑和子组件 支持少量通用属性参数
调用位置 必须在组件树构建过程中 (build 或其他 @Builder) 可以在组件定义时直接调用 .styleName()

4. 实战场景推荐

在实际项目中,以下场景非常适合使用 @Builder

  1. 列表项模板:如新闻列表、商品卡片、聊天消息气泡。
  2. 弹窗内容:将复杂的 Dialog 内容封装,使主页面代码清爽。
  3. 空状态页:统一的“无数据”、“网络错误”提示界面。
  4. 表单行:输入框 + 标签 + 校验信息的组合结构。

示例:封装一个空状态组件

@Builder
emptyStateView(message: string, imageResource: Resource) {
  Column() {
    Image(imageResource)
      .width(120)
      .height(120)
      .margin({ bottom: 16 })
    
    Text(message)
      .fontSize(14)
      .fontColor('#999999')
  }
  .width('100%')
  .justifyContent(FlexAlign.Center)
  .alignItems(HorizontalAlign.Center)
  .layoutWeight(1) // 占据剩余空间居中
}

// 调用
build() {
  Column() {
    if (this.dataList.length === 0) {
      this.emptyStateView('暂无数据', $r('sys.media.ohos_ic_public_empty'))
    } else {
      // 渲染列表...
    }
  }
}

总结

@Builder 是 ArkTS 声明式 UI 编程范式中的基石之一。通过合理地使用 @Builder

  • ✅ 你的代码将更具可读性
  • ✅ 你的组件将更具可维护性
  • ✅ 你的开发效率将显著提升。

建议在日常开发中,一旦发现某段 UI 代码出现第二次,就立即考虑将其抽取为 @Builder 函数。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐