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```