1、问题引入
我们在开发中可能会遇到这样一个问题:将一个@Builder修饰后的函数用变量或者数组记录下来,在业务其他地方使用这些@Builder函数。
举个例子,有下面一段代码:
@Builder
function builderElement() {}
let builderArr: Function[] = [builderElement];
@Builder
function testBuilder() {
ForEach(builderArr, (item: Function) => {
item();
})
}
我们试图将builderElement这个builder方法放到builderArr数组中,然后统一在另一个Builder方法(testBuilder)中遍历执行。
此时,我们在IDE中可以看到,会报一个如下的错误:
'item()' does not comply with the UI component syntax. <ArkTSCheck> |
为了解决这样的问题,ArkUI提供了wrapBuilder来让我们对Builder函数做封装。本文对wrapBuilder的使用做简单讨论。
2、wrapBuilder
wrapBuilder是一个模板函数,返回一个WrappedBuilder对象。其接口定义如下:
declare function wrapBuilder< Args extends Object[]>(builder: (...args: Args) => void): WrappedBuilder;
其中 WrappedBuilder对象也是一个模板类。定义如下:
// 模板参数<Args extends Object[]>是需要包装的builder函数的参数列表
declare class WrappedBuilder< Args extends Object[]> {
builder: (...args: Args) => void;
constructor(builder: (...args: Args) => void);
}
📢📢需要注意:
wrapBuilder方法只能传入全局@Builder方法。
wrapBuilder方法返回的WrappedBuilder对象的builder属性方法只能在struct内部使用。
3、案 例
我们有了wrapBuilder后,开篇的代码我们就可以改造为如下(注意第3行、第7 ~ 8行):
@Builder
function builderElement() {}
let builderArr: WrappedBuilder<[]>[] = [wrapBuilder(builderElement)];
@Builder
function testBuilder() {
ForEach(builderArr, (item: WrappedBuilder<[]>) => {
item.builder();
})
}
我们可以注意到第3行的WrappedBuilder定义,泛型参数是一个空数组,即:WrappedBuilder<[]>,表示我们包装的builder函数是空参数。
如果我们的builder函数有传入参数,那对应在数组中按顺序传入对应的类型即可。
例如,我们将builderElement改造为有两个入参的函数,第一个是string类型,第二个是number类型,那代码将是如下(第3行、第7 ~ 8行):
@Builder
function builderElement(name: string, count: number) {}
let builderArr: WrappedBuilder<[string, number]>[] = [wrapBuilder(builderElement)];
@Builder
function testBuilder() {
ForEach(builderArr, (item: WrappedBuilder<[string, number]>) => {
item.builder('欢迎加入【Harmony自习室】!', 1);
})
}
除了将wrappedBuilder放到数组中,我们也可以直接赋值给变量。一个案例如下(第7行、第17行):
@Builder
function MyBuilder(value: string, size: number) {
Text(value)
.fontSize(size)
}
let globalBuilder: WrappedBuilder<[string, number]> = wrapBuilder(MyBuilder);
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
build() {
Row() {
Column() {
globalBuilder.builder(this.message, 50)
}
.width('100%')
}
.height('100%')
}
}
‼️wrapBuilder不支持重复定义‼️
wrapBuilder(MyBuilderFirst)只在第一次定义时生效。即:
通过wrapBuilder(MyBuilderFirst)初始化定义builderObj之后,再次对builderObj进行赋值wrapBuilder(MyBuilderSecond)将不会起作用。示例代码如下:
@Builder
function MyBuilderFirst(value: string, size: number) {
Text('MyBuilderFirst:' + value)
.fontSize(size)
}
@Builder
function MyBuilderSecond(value: string, size: number) {
Text('MyBuilderSecond:' + value)
.fontSize(size)
}
interface BuilderModel {
globalBuilder: WrappedBuilder<[string, number]>;
}
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
@State builderObj: BuilderModel = { globalBuilder: wrapBuilder(MyBuilderFirst) };
aboutToAppear(): void {
setTimeout(() => {
this.builderObj.globalBuilder = wrapBuilder(MyBuilderSecond);
},1000)
}
build() {
Row() {
Column() {
this.builderObj.globalBuilder.builder(this.message, 20)
}
.width('100%')
}
.height('100%')
}
}