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