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