HarmonyOS鸿蒙Next中,@Builder装饰器如何创建可复用UI片段?@BuilderParam如何实现插槽?

HarmonyOS鸿蒙Next中,@Builder装饰器如何创建可复用UI片段?@BuilderParam如何实现插槽? 我想在 HarmonyOS 组件中复用 UI 代码片段,想了解:

  1. @Builder 装饰器的作用是什么?与普通方法有什么区别?

  2. 如何向 @Builder 方法传递参数?

  3. 组件内 @Builder 和全局 @Builder 有什么区别?

  4. @BuilderParam 如何实现类似 Vue 插槽(Slot)的功能?

  5. 如何将 @Builder 作为参数传递给子组件?

希望能获取 @Builder 的完整使用示例。


更多关于HarmonyOS鸿蒙Next中,@Builder装饰器如何创建可复用UI片段?@BuilderParam如何实现插槽?的实战教程也可以访问 https://www.itying.com/category-93-b0.html

3 回复

实现思路:

  1. 使用 @Builder 装饰器定义可复用的 UI 片段,可以接收参数:
[@Builder](/user/Builder)
TabItem(title: string, index: number) {
  Column() {
    Text(title)
      .fontSize(14)
      .fontColor(this.selectedIndex === index ? '#007AFF' : '#666')
    if (this.selectedIndex === index) {
      Divider().width(20).strokeWidth(2).color('#007AFF')
    }
  }
  .onClick(() => this.selectedIndex = index)
}
  1. 使用 @BuilderParam 定义插槽,允许父组件传入自定义内容:
@Component
struct SlotCard {
  @Prop title: string = '';
  [@BuilderParam](/user/BuilderParam) content: () => void = this.defaultContent;

  [@Builder](/user/Builder) defaultContent() {
    Text('默认内容')
  }

  build() {
    Column({ space: 12 }) {
      Text(this.title).fontSize(18).fontWeight(FontWeight.Bold)
      this.content()  // 渲染插槽内容
    }
    .padding(16)
    .backgroundColor('#FFF')
    .borderRadius(12)
  }
}
  1. 父组件使用插槽传入自定义内容:
SlotCard({ title: '自定义卡片' }) {
  Column({ space: 8 }) {
    Text('自定义内容第一行')
    Text('自定义内容第二行')
    Button('操作按钮')
  }
}
  1. 完整示例代码:
@Entry
@Component
struct BuilderExample {
  @State selectedIndex: number = 0;
  private tabs: string[] = ['首页', '分类', '我的'];

  // 组件内 [@Builder](/user/Builder)
  [@Builder](/user/Builder)
  TabItem(title: string, index: number) {
    Column() {
      Text(title)
        .fontSize(14)
        .fontColor(this.selectedIndex === index ? '#007AFF' : '#666')
      if (this.selectedIndex === index) {
        Divider()
          .width(20)
          .strokeWidth(2)
          .color('#007AFF')
          .margin({ top: 4 })
      }
    }
    .padding({ left: 16, right: 16, top: 8, bottom: 8 })
    .onClick(() => this.selectedIndex = index)
  }

  [@Builder](/user/Builder)
  customCardContent() {
    Column({ space: 8 }) {
      Text('这是自定义的卡片内容')
      Image($r('app.media.photo')).width('100%').height(100).borderRadius(8)
      Row({ space: 12 }) {
        Button('取消').backgroundColor('#F0F0F0').fontColor('#333')
        Button('确定').backgroundColor('#007AFF')
      }
    }
  }

  build() {
    Column({ space: 16 }) {
      // 使用 [@Builder](/user/Builder) 构建 Tab 栏
      Row({ space: 24 }) {
        ForEach(this.tabs, (tab: string, index: number) => {
          this.TabItem(tab, index)
        })
      }
      .width('100%')
      .justifyContent(FlexAlign.Center)
      .padding(12)
      .backgroundColor('#FFF')

      // 使用默认插槽
      SlotCard({ title: '默认内容卡片' })

      // 使用自定义插槽
      SlotCard({ title: '自定义内容卡片' }) {
        this.customCardContent()
      }
    }
    .width('100%')
    .height('100%')
    .padding(16)
    .backgroundColor('#F5F5F5')
  }
}

@Component
struct SlotCard {
  @Prop title: string = '';
  [@BuilderParam](/user/BuilderParam) content: () => void = this.defaultContent;

  [@Builder](/user/Builder) defaultContent() {
    Text('这是默认内容').fontColor('#999')
  }

  build() {
    Column({ space: 12 }) {
      Text(this.title).fontSize(18).fontWeight(FontWeight.Bold)
      this.content()
    }
    .width('100%')
    .padding(16)
    .backgroundColor('#FFF')
    .borderRadius(12)
  }
}

更多关于HarmonyOS鸿蒙Next中,@Builder装饰器如何创建可复用UI片段?@BuilderParam如何实现插槽?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


@Builder@BuilderParam装饰器

@Builder装饰器

@Builder装饰器用于创建可复用的UI片段,通过函数方式定义组件,支持参数传递。

@BuilderParam装饰器

@BuilderParam用于声明UI插槽,接收@Builder方法或闭包作为参数,实现动态UI组合。

结合使用

两者结合可实现灵活的自定义组件构建。

1. @Builder装饰器的作用与区别

@Builder装饰器用于构建可复用的UI描述片段,本质上是一个UI构建函数。与普通方法的核心区别在于:

  • 声明式UI@Builder方法内使用声明式UI语法(如Column、Text),而普通方法通常处理逻辑或返回数据。
  • this上下文@Builder方法内this指向所属组件实例,普通方法遵循标准函数作用域。
  • 调用方式@Builder方法通过花括号{}调用(如this.MyBuilder()),普通方法直接调用。

2. 向@Builder传递参数

支持两种参数传递方式:

  • 常规参数:直接传递基本类型或对象。
    [@Builder](/user/Builder)
    function MyBuilder(param1: string, param2: number) {
      Text(param1).fontSize(param2)
    }
    // 调用
    MyBuilder('Hello', 20)
    
  • TS方法引用:传递一个无返回值的函数类型参数。
    [@Builder](/user/Builder)
    function MyBuilder(action: () => void) {
      Button('Click').onClick(action)
    }
    

3. 组件内@Builder vs 全局@Builder

  • 组件内@Builder:定义在组件内,可访问组件状态(this),通过this.BuilderName()调用。
  • 全局@Builder:定义在组件外(如单独ts文件),无组件状态访问权限,通过函数名直接调用。

4. @BuilderParam实现插槽功能

@BuilderParam用于组件定义占位参数,接收@Builder类型参数实现动态UI插入:

// 子组件
@Component
struct ChildComponent {
  [@BuilderParam](/user/BuilderParam) content: () => void
  
  build() {
    Column() {
      this.content() // 插槽位置
    }
  }
}

// 父组件使用
@Entry
@Component
struct ParentComponent {
  [@Builder](/user/Builder) customSlot() {
    Text('插槽内容')
  }
  
  build() {
    Column() {
      ChildComponent({ content: this.customSlot }) // 传递Builder
    }
  }
}

5. 完整使用示例

// 全局Builder(无状态访问)
[@Builder](/user/Builder)
function GlobalBuilder(msg: string) {
  Text(msg).fontColor(Color.Red)
}

// 组件定义
@Component
struct MyComponent {
  [@State](/user/State) count: number = 0
  
  // 组件内Builder(可访问this)
  [@Builder](/user/Builder)
  private InnerBuilder(label: string) {
    Row() {
      Text(`${label}: ${this.count}`).fontSize(18)
    }
  }
  
  // 接收Builder参数
  [@BuilderParam](/user/BuilderParam) dynamicUI?: () => void
  
  build() {
    Column() {
      // 调用全局Builder
      GlobalBuilder('全局内容')
      
      // 调用组件内Builder
      this.InnerBuilder('计数')
      
      // 渲染动态插槽
      if (this.dynamicUI) {
        this.dynamicUI()
      }
      
      Button('增加').onClick(() => { this.count++ })
    }
  }
}

// 使用组件并传递Builder
@Entry
@Component
struct ParentComponent {
  [@Builder](/user/Builder) customBuilder() {
    Column() {
      Text('自定义插槽').fontWeight(FontWeight.Bold)
      Divider().strokeWidth(2)
    }
  }
  
  build() {
    Column() {
      MyComponent({ dynamicUI: this.customBuilder })
    }
  }
}

关键点总结

  • @BuilderParam必须与@Builder配合使用,实现UI片段参数化
  • 组件内Builder可响应状态变化(如@State
  • 通过TS函数类型约束Builder参数格式
  • 插槽内容在子组件中通过this.builderParamName()渲染
回到顶部