鸿蒙中 @BuilderParam装饰器
摘要:ArkUI的@BuilderParam装饰器解决了HarmonyOS自定义组件功能固化问题,支持通过父组件动态注入@Builder方法实现灵活定制。该装饰器支持本地初始化、父组件初始化两种方式,并可通过尾随闭包简化传参。使用时需注意this指向问题(箭头函数可保持父组件上下文)和参数类型匹配,且必须用@Builder方法初始化。典型应用场景包括参数化组件、尾随闭包初始化和V2组件模型集成,能
本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
鸿蒙开发中,当创建自定义组件时,经常会遇到这样的需求:需要为组件添加特定功能(如页面跳转、点击事件等),但如果直接在组件内嵌入事件方法,会导致所有该组件的实例都具备相同的功能,缺乏灵活性。为了解决这个问题,ArkUI引入了@BuilderParam装饰器。
@BuilderParam用于装饰指向@Builder方法的变量,允许在初始化自定义组件时,通过不同的方式对@BuilderParam装饰的自定义构建函数进行传参赋值,从而实现组件功能的灵活定制。
一、@BuilderParam装饰器
@BuilderParam装饰器用于接收@Builder装饰的函数,将其作为参数传递给自定义组件,使得父组件可以动态决定子组件的UI结构或行为。
核心作用
-
解耦组件功能:将特定功能从组件内部剥离,由父组件按需注入
-
提高复用性:同一个组件可以通过不同的@BuilderParam实现不同的展示效果
-
灵活定制:支持多种传参方式(参数修改、尾随闭包、箭头函数等)
支持版本
| 版本 | 支持范围 |
|---|---|
| API version 7 | 开始支持 |
| API version 9+ | 支持在ArkTS卡片中使用 |
| API version 11+ | 支持在元服务中使用 |
二、装饰器使用
2.1 基本语法
@BuilderParam variableName: () => void = initialBuilderFunction;
2.2 初始化方式
@BuilderParam装饰的方法只能被自定义构建函数(@Builder装饰的方法)初始化。
方式一:本地初始化
使用所属自定义组件的自定义构建函数或全局自定义构建函数,在本地初始化@BuilderParam。
@Builder
function overBuilder() {
Text('全局Builder')
}
@Component
struct Child {
@Builder
doNothingBuilder() {
Text('本地Builder')
}
// 使用自定义组件的自定义构建函数初始化
@BuilderParam customBuilderParam: () => void = this.doNothingBuilder;
// 使用全局自定义构建函数初始化
@BuilderParam customOverBuilderParam: () => void = overBuilder;
build() {
Column() {
this.customBuilderParam()
this.customOverBuilderParam()
}
}
}
方式二:父组件初始化
使用父组件的自定义构建函数初始化子组件的@BuilderParam。
@Component
struct Child {
@Builder
customBuilder() {
Text('默认Builder')
}
@BuilderParam customBuilderParam: () => void = this.customBuilder;
build() {
Column() {
this.customBuilderParam() // 调用注入的Builder
}
}
}
@Entry
@Component
struct Parent {
@Builder
componentBuilder() {
Text('Parent builder')
}
build() {
Column() {
// 将父组件的Builder注入子组件
Child({ customBuilderParam: this.componentBuilder })
}
}
}
2.3 this指向问题
在传递@Builder时,需要注意this的指向,它会影响Builder内部访问的变量值。
@Component
struct Child {
label: string = 'Child';
@Builder
customBuilder() { }
@Builder
customChangeThisBuilder() { }
@BuilderParam customBuilderParam: () => void = this.customBuilder;
@BuilderParam customChangeThisBuilderParam: () => void = this.customChangeThisBuilder;
build() {
Column() {
this.customBuilderParam()
this.customChangeThisBuilderParam()
}
}
}
@Entry
@Component
struct Parent {
label: string = 'Parent';
@Builder
componentBuilder() {
Text(`${this.label}`) // 这里的this取决于调用时的上下文
}
build() {
Column() {
// 直接调用,this指向Parent,显示"Parent"
this.componentBuilder()
Child({
// 直接传递Builder,this会指向子组件Child,显示"Child"
customBuilderParam: this.componentBuilder,
// 使用箭头函数包装,this指向父组件Parent,显示"Parent"
customChangeThisBuilderParam: (): void => {
this.componentBuilder()
}
})
}
}
}
说明:
-
customBuilderParam:显示"Child"(this指向子组件) -
customChangeThisBuilderParam:显示"Parent"(箭头函数保持父组件this)
三、限制条件
3.1 初始化值必须为@Builder
@BuilderParam装饰的变量只能通过@Builder函数进行初始化,不能使用普通变量或状态变量。
3.2 与@Require联用的限制
当@Require装饰器和@BuilderParam装饰器一起使用时,必须从外部初始化@BuilderParam装饰器。
3.3 尾随闭包的限制
在自定义组件尾随闭包的场景下:
-
子组件有且仅有一个@BuilderParam用来接收此尾随闭包
-
此@BuilderParam装饰的方法不能有参数
-
此场景下自定义组件不支持通用属性
// 只有一个无参@BuilderParam
@Component
struct CustomContainer {
@BuilderParam closer: () => void; // 只能有一个,且无参
build() {
Column() {
this.closer()
}
}
}
// 使用尾随闭包
CustomContainer() {
// 尾随闭包内容
Text('这是尾随闭包内容')
}
四、使用场景
4.1 场景一:参数初始化组件
@BuilderParam装饰的方法可以是有参数或无参数的形式,但必须与指向的@Builder方法类型匹配。
class Tmp {
public label: string = '';
}
@Builder
function overBuilder($$: Tmp) {
Text($$.label)
.width('100%')
.height(50)
.backgroundColor(Color.Green)
}
@Component
struct Child {
label: string = 'Child';
@Builder
customBuilder() {
Text('默认Builder')
}
// 无参数类型
@BuilderParam customBuilderParam: () => void = this.customBuilder;
// 有参数类型
@BuilderParam customOverBuilderParam: ($$: Tmp) => void = overBuilder;
build() {
Column() {
this.customBuilderParam()
this.customOverBuilderParam({ label: 'global Builder label' })
}
}
}
@Entry
@Component
struct Parent {
label: string = 'Parent';
@Builder
componentBuilder() {
Text(`${this.label}`)
}
build() {
Column() {
this.componentBuilder()
Child({
customBuilderParam: this.componentBuilder,
customOverBuilderParam: overBuilder
})
}
}
}
4.2 场景二:尾随闭包初始化组件
尾随闭包是一种特殊的初始化方式,允许在创建组件时,通过紧跟一个大括号{}来传递Builder内容。
示例1:基础尾随闭包用法
@Component
struct CustomContainer {
@Prop header: string = '';
@Builder
closerBuilder() { }
// 使用父组件的尾随闭包初始化
@BuilderParam closer: () => void = this.closerBuilder;
build() {
Column() {
Text(this.header).fontSize(30)
this.closer() // 调用尾随闭包传入的内容
}
}
}
@Builder
function specificParam(label1: string, label2: string) {
Column() {
Text(label1).fontSize(30)
Text(label2).fontSize(30)
}
}
@Entry
@Component
struct CustomContainerUser {
@State text: string = 'header';
build() {
Column() {
// 使用尾随闭包传递Builder内容
CustomContainer({ header: this.text }) {
Column() {
specificParam('testA', 'testB')
}
.backgroundColor(Color.Yellow)
.onClick(() => {
this.text = 'changeHeader';
})
}
}
}
}
示例2:与@ComponentV2结合使用
@ComponentV2
struct ChildPage {
@Require @Param message: string = '';
@Builder
customBuilder() { }
@BuilderParam customBuilderParam: () => void = this.customBuilder;
build() {
Column() {
Text(this.message).fontSize(30).fontWeight(FontWeight.Bold)
this.customBuilderParam()
}
}
}
const builderValue: string = 'Hello World';
@Builder
function overBuilder() {
Row() {
Text(`Global Builder: ${builderValue}`)
.fontSize(20)
.fontWeight(FontWeight.Bold)
}
}
@Entry
@ComponentV2
struct ParentPage {
@Local label: string = 'Parent Page';
@Builder
componentBuilder() {
Row() {
Text(`Local Builder: ${this.label}`)
.fontSize(20)
.fontWeight(FontWeight.Bold)
}
}
build() {
Column() {
// 使用局部@Builder的尾随闭包
ChildPage({ message: this.label }) {
Column() {
this.componentBuilder();
}
}
Line().width('100%').height(10).backgroundColor('#000000').margin(10)
// 使用全局@Builder的尾随闭包
ChildPage({ message: this.label }) {
Column() {
overBuilder();
}
}
}
}
}
4.3 场景三:使用全局和局部@Builder初始化@BuilderParam
通过不同的传递方式,控制Builder内部的this指向,实现不同的展示效果。
@Component
struct ChildPage {
label: string = 'Child Page';
@Builder
customBuilder() { }
@BuilderParam customBuilderParam: () => void = this.customBuilder;
@BuilderParam customChangeThisBuilderParam: () => void = this.customBuilder;
build() {
Column() {
this.customBuilderParam()
this.customChangeThisBuilderParam()
}
}
}
const builderValue: string = 'Hello World';
@Builder
function overBuilder() {
Row() {
Text(`Global Builder: ${builderValue}`)
.fontSize(20)
.fontWeight(FontWeight.Bold)
}
}
@Entry
@Component
struct ParentPage {
label: string = 'Parent Page';
@Builder
componentBuilder() {
Row() {
Text(`Local Builder: ${this.label}`)
.fontSize(20)
.fontWeight(FontWeight.Bold)
}
}
build() {
Column() {
// 直接调用,显示"Parent Page"
this.componentBuilder()
ChildPage({
// 直接传递,this指向子组件,显示"Child Page"
customBuilderParam: this.componentBuilder,
// 箭头函数包装,this指向父组件,显示"Parent Page"
customChangeThisBuilderParam: (): void => {
this.componentBuilder()
}
})
Line().width('100%').height(10).backgroundColor('#000000').margin(10)
// 调用全局Builder,显示"Hello World"
overBuilder()
ChildPage({
// 传递全局Builder,都显示"Hello World"
customBuilderParam: overBuilder,
customChangeThisBuilderParam: overBuilder
})
}
}
}
4.5 场景五:在@ComponentV2中使用@BuilderParam
在V2版本的组件模型中,@BuilderParam同样可以配合全局或局部@Builder使用。
@ComponentV2
struct ChildPage {
@Param label: string = 'Child Page';
@Builder
customBuilder() { }
@BuilderParam customBuilderParam: () => void = this.customBuilder;
@BuilderParam customChangeThisBuilderParam: () => void = this.customBuilder;
build() {
Column() {
this.customBuilderParam()
this.customChangeThisBuilderParam()
}
}
}
const builderValue: string = 'Hello World';
@Builder
function overBuilder() {
Row() {
Text(`Global Builder: ${builderValue}`)
.fontSize(20)
.fontWeight(FontWeight.Bold)
}
}
@Entry
@ComponentV2
struct ParentPage {
@Local label: string = 'Parent Page';
@Builder
componentBuilder() {
Row() {
Text(`Local Builder: ${this.label}`)
.fontSize(20)
.fontWeight(FontWeight.Bold)
}
}
build() {
Column() {
// 直接调用,显示"Parent Page"
this.componentBuilder()
ChildPage({
customBuilderParam: this.componentBuilder, // 显示"Child Page"
customChangeThisBuilderParam: (): void => { // 显示"Parent Page"
this.componentBuilder()
}
})
Line().width('100%').height(5).backgroundColor('#000000').margin(10)
// 全局Builder
overBuilder() // 显示"Hello World"
ChildPage({
customBuilderParam: overBuilder, // 都显示"Hello World"
customChangeThisBuilderParam: overBuilder
})
}
}
}
注意事项:
-
必须用@Builder初始化:普通变量不行
-
类型必须匹配:参数签名要一致
-
注意this指向:箭头函数可以保持父组件上下文
-
尾随闭包特殊:只能有一个且无参
更多推荐


所有评论(0)