Skip to content

自定义组件之插槽

笔者在前 5 节讲述的自定义组件的实现和使用中有一种情形并没有介绍,就是开发者在使用我们提供的自定义组件的时候如果想往自定义组件内添加一些额外的子组件,在不修改我们组件源码的情况下该如何实现喃?对于这种场景,ArkUI 开发框架提供了 @BuilderParam 修饰符来解决这种问题,本节笔者就简单介绍一下 @BuilderParam 修饰符的使用。

@BuilderParam 属性发现

笔者在学习自定义组件的时候,突发奇想,如果自定义组件返回的是一个容器布局结构,那么直接给自定义组件添加一个子组件是不是可行?于是笔者做了如下实验,首先定义了一个组件 CustomWidget ,代码如下:

bash

@Component struct CustomWidget {
  build() {
    Column() {
    }
    .width("100%")
    .height(100)
    .backgroundColor("#aabbcc")
  }
}

自定义的组件 CustomWidget 返回一个带有背景色的 Column ,因为它返回的是一个容器组件,笔者就想当然的认为可以像使用其它容器组件一样直接给 CustomWidget 组件添加子组件,于是就尝试了一下,代码写法如下所示:

bash

@Entry @Component struct CustomWidgetTest {
  build() {
    Column() {
      CustomWidget() {   // 使用CustomWidget组件并给它添加了一个子组件Text
        Text('测试子组件') // 添加子组件后编译报错
      }
    }
    .width('100%')
    .height('100%')
  }
}

笔者打开 Previewer 准备看下运行效果,结果编译报错,报错信息如下所示:

bash

[Compile Result]  ETS:ERROR File: ***/entry/src/main/ets/MainAbility/pages/index.ets:4:7
[Compile Result]  In the trailing lambda case, 'CustomWidget' must have one and only one property decorated with @BuilderParam, and its @BuilderParam expects no parameter.

根据报错信息提示,组件 CustomWidget 必须有且只有一个 @BuilderParam 修饰的属性且该属性不需要参数。这就是笔者发现 @BuilderParam 修饰符的由来。

@BuilderParam 属性定义

bash

/**
 * Defining BuilderParam PropertyDecorator
 * @since 7
 */
declare const BuilderParam: PropertyDecorator;

BuilderParam 定义在 common.d.ts 文件中,它是一个属性修饰符,修饰的属性类型为 () => {} ,因此需要在自定义组件 CustomWidget 内部声明一个属性,比如 child,代码如下所示:

bash

@Component struct CustomWidget {

  @BuilderParam child: () => {}; // 声明属性child,该属性返回一个对象。

  // 省略部分代码
}

@BuilderParam 使用介绍

CustomWidget 组件添加 child 属性后,表示该组件具备了额外添加子组件的能力,接下来在需要添加子组件的地方使用 child 属性做占位即可,代码如下所示:

bash

@Component struct CustomWidget {

  @BuilderParam child: () => {}

  build() {
    Column() {
      Text('原始子组件1')
        .fontSize(20)
      this.child()      // 在这里插入额外的子组件
      Text('原始子组件2')
        .fontSize(20)
      this.child()      // 在这里插入额外的子组件
    }
    .width('100%')
    .backgroundColor("#aabbcc")
  }
}

CustomWidget 组件添加完占位后,就可以直接给其添加子组件了,代码如下所示:

bash

@Entry @Component struct CustomWidgetTest {
  build() {
    Column() {
      CustomWidget() {      // 使用CustomWidget组件并给它添加了两个子组件Text
        Text('添加子组件aaa') // 添加子组件
          .fontSize(20)
          .backgroundColor(Color.Pink)
        Text('添加子组件bbb') // 添加子组件
          .fontSize(20)
          .backgroundColor(Color.Pink)
      }
    }
    .width('100%')
    .height('100%')
  }
}

运行结果如下图所示:

图片