1# wrapBuilder:封装全局@Builder
2
3  当开发者在一个struct内使用了多个全局@Builder函数,来实现UI的不同效果时,多个全局@Builder函数会使代码维护起来非常困难,并且页面不整洁。此时,开发者可以使用wrapBuilder来封装全局@Builder。
4
5  在阅读本文档前,建议提前阅读:[\@Builder](./arkts-builder.md)。
6
7> **说明:**
8>
9> 从API version 11开始使用。
10
11当@Builder方法赋值给变量或者数组后,赋值的变量或者数组在UI方法中无法使用。
12
13```ts
14@Builder
15function builderElement() {}
16
17let builderArr: Function[] = [builderElement];
18@Builder
19function testBuilder() {
20  ForEach(builderArr, (item: Function) => {
21    item();
22  })
23}
24```
25
26在上述代码中,builderArr是一个@Builder方法组成的数组, 在ForEach中取每一项@Builder方法时会出现@Builder方法在UI方法中无法使用的错误。
27
28 为了解决这一问题,引入wrapBuilder作为全局@Builder封装函数。wrapBuilder的参数返回WrappedBuilder对象,实现[全局\@Builder](arkts-builder.md#全局自定义构建函数)可以进行赋值和传递。
29
30## 接口说明
31
32wrapBuilder是一个模板函数,返回一个`WrappedBuilder`对象。
33
34```ts
35declare function wrapBuilder< Args extends Object[]>(builder: (...args: Args) => void): WrappedBuilder;
36```
37同时 `WrappedBuilder`对象也是一个模板类。
38
39```ts
40declare class WrappedBuilder< Args extends Object[]> {
41  builder: (...args: Args) => void;
42
43  constructor(builder: (...args: Args) => void);
44}
45```
46
47
48>说明:模板参数`Args extends Object[]`是需要包装的builder函数的参数列表
49
50使用方法:
51
52```ts
53let builderVar: WrappedBuilder<[string, number]> = wrapBuilder(MyBuilder)
54let builderArr: WrappedBuilder<[string, number]>[] = [wrapBuilder(MyBuilder)] //可以放入数组
55```
56
57
58
59## 限制条件
60
61wrapBuilder方法只能传入[全局\@Builder](arkts-builder.md#全局自定义构建函数)方法。
62
63wrapBuilder方法返回的WrappedBuilder对象的builder属性方法只能在struct内部使用。
64
65
66
67## @Builder方法赋值给变量
68
69把@Builder装饰器装饰的方法MyBuilder作为wrapBuilder的参数,再将wrapBuilder赋值给变量globalBuilder,用来解决@Builder方法赋值给变量后无法被使用的问题。
70
71```ts
72@Builder
73function MyBuilder(value: string, size: number) {
74  Text(value)
75    .fontSize(size)
76}
77
78let globalBuilder: WrappedBuilder<[string, number]> = wrapBuilder(MyBuilder);
79
80@Entry
81@Component
82struct Index {
83  @State message: string = 'Hello World';
84
85  build() {
86    Row() {
87      Column() {
88        globalBuilder.builder(this.message, 50)
89      }
90      .width('100%')
91    }
92    .height('100%')
93  }
94}
95```
96
97##  @Builder方法赋值给变量在UI语法中使用
98
99自定义组件Index使用ForEach来进行不同\@Builder函数的渲染,可以使用builderArr声明的wrapBuilder数组进行不同\@Builder函数效果体现。整体代码会较整洁。
100
101```
102@Builder
103function MyBuilder(value: string, size: number) {
104  Text(value)
105    .fontSize(size)
106}
107
108@Builder
109function YourBuilder(value: string, size: number) {
110  Text(value)
111    .fontSize(size)
112    .fontColor(Color.Pink)
113}
114
115const builderArr: WrappedBuilder<[string, number]>[] = [wrapBuilder(MyBuilder), wrapBuilder(YourBuilder)];
116
117
118@Entry
119@Component
120struct Index {
121  @Builder testBuilder() {
122    ForEach(builderArr, (item: WrappedBuilder<[string, number]>) => {
123      item.builder('Hello World', 30)
124    }
125
126    )
127  }
128
129  build() {
130    Row() {
131      Column() {
132        this.testBuilder()
133      }
134      .width('100%')
135    }
136    .height('100%')
137  }
138}
139```
140
141## 引用传递
142
143通过按引用传递的方式传入参数,会触发UI的刷新。
144
145```ts
146class Tmp {
147  paramA2: string = 'hello';
148}
149
150@Builder function overBuilder(param: Tmp) {
151  Column(){
152    Text(`wrapBuildervalue:${param.paramA2}`)
153  }
154}
155
156const wBuilder: WrappedBuilder<[Tmp]> = wrapBuilder(overBuilder);
157
158@Entry
159@Component
160struct Parent{
161  @State label: Tmp = new Tmp();
162  build(){
163    Column(){
164      wBuilder.builder({paramA2: this.label.paramA2})
165      Button('Click me').onClick(() => {
166        this.label.paramA2 = 'ArkUI';
167      })
168    }
169  }
170}
171```
172
173## 错误场景
174
175### 重复定义wrapBuilder失效
176
177通过wrapBuilder(MyBuilderFirst)初始化定义builderObj之后,再次对builderObj进行赋值wrapBuilder(MyBuilderSecond)会不起作用,只生效第一次定义的wrapBuilder(MyBuilderFirst)。
178
179```ts
180@Builder
181function MyBuilderFirst(value: string, size: number) {
182  Text('MyBuilderFirst:' + value)
183    .fontSize(size)
184}
185
186@Builder
187function MyBuilderSecond(value: string, size: number) {
188  Text('MyBuilderSecond:' + value)
189    .fontSize(size)
190}
191
192interface BuilderModel {
193  globalBuilder: WrappedBuilder<[string, number]>;
194}
195
196@Entry
197@Component
198struct Index {
199  @State message: string = 'Hello World';
200  @State builderObj: BuilderModel = { globalBuilder: wrapBuilder(MyBuilderFirst) };
201
202  aboutToAppear(): void {
203    setTimeout(() => {
204      this.builderObj.globalBuilder = wrapBuilder(MyBuilderSecond);
205    },1000)
206  }
207
208  build() {
209    Row() {
210      Column() {
211        this.builderObj.globalBuilder.builder(this.message, 20)
212      }
213      .width('100%')
214    }
215    .height('100%')
216  }
217}
218```