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