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%')
? }
}