1# \@Builder装饰器:自定义构建函数 2 3ArkUI提供了一种轻量的UI元素复用机制\@Builder,其内部UI结构固定,仅与使用方进行数据传递,开发者可以将重复使用的UI元素抽象成一个方法,在build方法里调用。 4 5为了简化语言,我们将\@Builder装饰的函数也称为“自定义构建函数”。 6 7在阅读本文档前,建议提前阅读:[基本语法概述](./arkts-basic-syntax-overview.md),[声明式UI描述](./arkts-declarative-ui-description.md),[自定义组件-创建自定义组件](./arkts-create-custom-components.md)。 8 9> **说明:** 10> 11> 从API version 9开始,该装饰器支持在ArkTS卡片中使用。 12> 13> 从API version 11开始,该装饰器支持在原子化服务中使用。 14 15 16## 装饰器使用说明 17 18\@Builder装饰器有两种使用方式,分别是定义在自定义组件内部的私有自定义构建函数和定义在全局的全局自定义构建函数。 19 20### 私有自定义构建函数 21 22定义的语法: 23 24```ts 25@Entry 26@Component 27struct BuilderDemo { 28 @Builder 29 showTextBuilder() { 30 Text('Hello World') 31 .fontSize(30) 32 .fontWeight(FontWeight.Bold) 33 } 34 @Builder 35 showTextValueBuilder(param: string) { 36 Text(param) 37 .fontSize(30) 38 .fontWeight(FontWeight.Bold) 39 } 40 build() { 41 Column() { 42 // 无参数 43 this.showTextBuilder() 44 // 有参数 45 this.showTextValueBuilder('Hello @Builder') 46 } 47 } 48} 49``` 50 51使用方法: 52 53```ts 54this.showTextBuilder() 55``` 56 57- 允许在自定义组件内定义一个或多个@Builder方法,该方法被认为是该组件的私有、特殊类型的成员函数。 58 59- 私有自定义构建函数允许在自定义组件内、build方法和其他自定义构建函数中调用。 60 61- 在自定义函数体中,this指代当前所属组件,组件的状态变量可以在自定义构建函数内访问。建议通过this访问自定义组件的状态变量而不是参数传递。 62 63 64### 全局自定义构建函数 65 66定义的语法: 67 68```ts 69@Builder 70function showTextBuilder() { 71 Text('Hello World') 72 .fontSize(30) 73 .fontWeight(FontWeight.Bold) 74} 75@Entry 76@Component 77struct BuilderDemo { 78 build() { 79 Column() { 80 showTextBuilder() 81 } 82 } 83} 84``` 85 86使用方法: 87 88```ts 89showTextBuilder() 90``` 91 92- 如果不涉及组件状态变化,建议使用全局的自定义构建方法。 93 94- 全局自定义构建函数允许在build方法和其他自定义构建函数中调用。 95 96 97## 参数传递规则 98 99自定义构建函数的参数传递有[按值传递](#按值传递参数)和[按引用传递](#按引用传递参数)两种,均需遵守以下规则: 100 101- 参数的类型必须与参数声明的类型一致,不允许undefined、null和返回undefined、null的表达式。 102 103- 在@Builder修饰的函数内部,不允许改变参数值。 104 105- \@Builder内UI语法遵循[UI语法规则](arkts-create-custom-components.md#build函数)。 106 107- 只有传入一个参数,且参数需要直接传入对象字面量才会按引用传递该参数,其余传递方式均为按值传递。 108 109### 按值传递参数 110 111调用\@Builder装饰的函数默认按值传递。当传递的参数为状态变量时,状态变量的改变不会引起\@Builder方法内的UI刷新。所以当使用状态变量的时候,推荐使用[按引用传递](#按引用传递参数)。 112 113```ts 114@Builder function overBuilder(paramA1: string) { 115 Row() { 116 Text(`UseStateVarByValue: ${paramA1} `) 117 } 118} 119@Entry 120@Component 121struct Parent { 122 @State label: string = 'Hello'; 123 build() { 124 Column() { 125 overBuilder(this.label) 126 } 127 } 128} 129``` 130 131### 按引用传递参数 132 133按引用传递参数时,传递的参数可为状态变量,且状态变量的改变会引起\@Builder方法内的UI刷新。 134 135```ts 136class Tmp { 137 paramA1: string = ''; 138} 139 140@Builder function overBuilder(params: Tmp) { 141 Row() { 142 Text(`UseStateVarByReference: ${params.paramA1} `) 143 } 144} 145@Entry 146@Component 147struct Parent { 148 @State label: string = 'Hello'; 149 build() { 150 Column() { 151 // 在父组件中调用overBuilder组件时, 152 // 把this.label通过引用传递的方式传给overBuilder组件。 153 overBuilder({ paramA1: this.label }) 154 Button('Click me').onClick(() => { 155 // 单击Click me后,UI文本从Hello更改为ArkUI。 156 this.label = 'ArkUI'; 157 }) 158 } 159 } 160} 161``` 162 163## 限制条件 164 1651. \@Builder装饰的函数内部,不允许修改参数值,否则框架会抛出运行时错误。开发者可以在调用\@Builder的自定义组件里改变其参数。请参考[在@Builder装饰的函数内部修改入参内容](#在builder装饰的函数内部修改入参内容)。 166 1672. \@Builder通过按引用传递的方式传入参数,才会触发动态渲染UI,并且参数只能是一个。请参考[按引用传递参数](#按引用传递参数)。 168 1693. \@Builder如果传入的参数是两个或两个以上,不会触发动态渲染UI。请参考[@Builder存在两个或者两个以上参数](#builder存在两个或者两个以上参数)。 170 1714. \@Builder传入的参数中同时包含按值传递和按引用传递两种方式,不会触发动态渲染UI。请参考[@Builder存在两个或者两个以上参数](#builder存在两个或者两个以上参数)。 172 1735. \@Builder的参数必须按照对象字面量的形式,把所需要的属性一一传入,才会触发动态渲染UI。请参考[@Builder存在两个或者两个以上参数](#builder存在两个或者两个以上参数)。 174 175 176## 使用场景 177 178### 自定义组件内使用自定义构建函数 179 180创建私有的\@Builder方法,在Column里面使用this.builder()方式调用,通过aboutToAppear生命周期函数和按钮的点击事件改变builder_value的内容,实现动态渲染UI。 181 182```ts 183@Entry 184@Component 185struct PrivateBuilder { 186 @State builder_value: string = 'Hello'; 187 188 @Builder builder() { 189 Column(){ 190 Text(this.builder_value) 191 .fontSize(30) 192 .fontWeight(FontWeight.Bold) 193 } 194 } 195 196 aboutToAppear(): void { 197 setTimeout(() => { 198 this.builder_value = 'Hello World'; 199 },3000) 200 } 201 202 build() { 203 Row() { 204 Column() { 205 Text(this.builder_value) 206 .fontSize(30) 207 .fontWeight(FontWeight.Bold) 208 this.builder() 209 Button('点击改变builder_value内容') 210 .onClick(() => { 211 this.builder_value ='builder_value被点击了'; 212 }) 213 } 214 } 215 } 216} 217``` 218 219### 使用全局自定义构建函数 220 221创建全局的\@Builder方法,在Column里面使用overBuilder()方式调用,通过以对象字面量的形式传递参数,无论是简单类型还是复杂类型,值的改变都会引起UI界面的刷新。 222 223```ts 224class ChildTmp { 225 val: number = 1; 226} 227 228class Tmp { 229 str_value: string = 'Hello'; 230 num_value: number = 0; 231 tmp_value: ChildTmp = new ChildTmp(); 232 arrayTmp_value: Array<ChildTmp> = []; 233} 234 235@Builder function overBuilder(param: Tmp) { 236 Column() { 237 Text(`str_value: ${param.str_value}`) 238 Text(`num_value: ${param.num_value}`) 239 Text(`tmp_value: ${param.tmp_value.val}`) 240 ForEach(param.arrayTmp_value, (item: ChildTmp) => { 241 Text(`arrayTmp_value: ${item.val}`) 242 }, (item: ChildTmp) => JSON.stringify(item)) 243 } 244} 245 246@Entry 247@Component 248struct Parent { 249 @State objParam: Tmp = new Tmp(); 250 build() { 251 Column() { 252 Text('通过调用@Builder渲染UI界面') 253 .fontSize(20) 254 overBuilder({str_value: this.objParam.str_value, num_value: this.objParam.num_value, 255 tmp_value: this.objParam.tmp_value, arrayTmp_value: this.objParam.arrayTmp_value}) 256 Line() 257 .width('100%') 258 .height(10) 259 .backgroundColor('#000000').margin(10) 260 Button('点击改变参数值').onClick(() => { 261 this.objParam.str_value = 'Hello World'; 262 this.objParam.num_value = 1; 263 this.objParam.tmp_value.val = 8; 264 const child_value: ChildTmp = { 265 val: 2 266 } 267 this.objParam.arrayTmp_value.push(child_value) 268 }) 269 } 270 } 271} 272``` 273 274### 修改装饰器修饰的变量触发UI刷新 275 276此种场景@Builder只是用来展示Text组件,没有参与动态UI刷新的功能,Text组件中值的变化是使用了装饰器的特性,监听到值的改变触发的UI刷新,而不是通过\@Builder的能力触发的。 277 278```ts 279class Tmp { 280 str_value: string = 'Hello'; 281} 282 283@Entry 284@Component 285struct Parent { 286 @State objParam: Tmp = new Tmp(); 287 @State label: string = 'World'; 288 289 @Builder privateBuilder() { 290 Column() { 291 Text(`wrapBuilder str_value: ${this.objParam.str_value}`) 292 Text(`wrapBuilder num: ${this.label}`) 293 } 294 } 295 296 build() { 297 Column() { 298 Text('通过调用@Builder渲染UI界面') 299 .fontSize(20) 300 this.privateBuilder() 301 Line() 302 .width('100%') 303 .height(10) 304 .backgroundColor('#000000').margin(10) 305 Button('点击改变参数值').onClick(() => { 306 this.objParam.str_value = 'str_value Hello World'; 307 this.label = 'label Hello World' 308 }) 309 } 310 } 311} 312``` 313 314### 使用全局和局部的@Builder传入customBuilder类型 315 316当某个参数类型为customBuilder的时候,可以把定义的\@Builder函数传入,因为customBuilder实际是一个Function(() => any)或者是void类型,而\@Builder实际也是一个Function类型。此场景中通过把\@Builder传入已实现特定的效果。 317 318```ts 319@Builder 320function overBuilder() { 321 Row() { 322 Text('全局 Builder') 323 .fontSize(30) 324 .fontWeight(FontWeight.Bold) 325 } 326} 327 328@Entry 329@Component 330struct customBuilderDemo { 331 @State arr: number[] = [0, 1, 2, 3, 4]; 332 333 @Builder 334 privateBuilder() { 335 Row() { 336 Text('局部 Builder') 337 .fontSize(30) 338 .fontWeight(FontWeight.Bold) 339 } 340 } 341 342 build() { 343 Column() { 344 List({ space: 10 }) { 345 ForEach(this.arr, (item: number) => { 346 ListItem() { 347 Text(`${item}`) 348 .width('100%') 349 .height(100) 350 .fontSize(16) 351 .textAlign(TextAlign.Center) 352 .borderRadius(10) 353 .backgroundColor(0xFFFFFF) 354 } 355 .swipeAction({ 356 start: { 357 builder: overBuilder() 358 }, 359 end: { 360 builder: () => { 361 this.privateBuilder() 362 } 363 } 364 }) 365 }, (item: number) => JSON.stringify(item)) 366 } 367 } 368 } 369} 370``` 371 372### 多层\@Builder方法嵌套使用 373 374在\@Builder方法内调用自定义组件或者其他\@Builder方法,以实现多个\@Builder嵌套使用的场景,要想实现最里面的\@Builder动态UI刷新功能,必须要保证每层调用\@Builder的地方使用按引用传递的方式。这里的[\$$](./arkts-two-way-sync.md)也可以换成其他名称,[\$$](./arkts-two-way-sync.md)不是必须的参数形式。 375 376```ts 377class Tmp { 378 paramA1: string = ''; 379} 380 381@Builder function parentBuilder($$: Tmp) { 382 Row() { 383 Column() { 384 Text(`parentBuilder===${$$.paramA1}`) 385 .fontSize(30) 386 .fontWeight(FontWeight.Bold) 387 HelloComponent({message: $$.paramA1}) 388 childBuilder({paramA1: $$.paramA1}) 389 } 390 } 391} 392 393@Component 394struct HelloComponent { 395 @Prop message: string = ''; 396 397 build() { 398 Row() { 399 Text(`HelloComponent===${this.message}`) 400 .fontSize(30) 401 .fontWeight(FontWeight.Bold) 402 } 403 } 404} 405 406@Builder 407function childBuilder($$: Tmp) { 408 Row() { 409 Column() { 410 Text(`childBuilder===${$$.paramA1}`) 411 .fontSize(30) 412 .fontWeight(FontWeight.Bold) 413 HelloChildComponent({message: $$.paramA1}) 414 grandsonBuilder({paramA1: $$.paramA1}) 415 } 416 } 417} 418 419@Component 420struct HelloChildComponent { 421 @Prop message: string = ''; 422 build() { 423 Row() { 424 Text(`HelloChildComponent===${this.message}`) 425 .fontSize(30) 426 .fontWeight(FontWeight.Bold) 427 } 428 } 429} 430 431@Builder function grandsonBuilder($$: Tmp) { 432 Row() { 433 Column() { 434 Text(`grandsonBuilder===${$$.paramA1}`) 435 .fontSize(30) 436 .fontWeight(FontWeight.Bold) 437 HelloGrandsonComponent({message: $$.paramA1}) 438 } 439 } 440} 441 442@Component 443struct HelloGrandsonComponent { 444 @Prop message: string; 445 build() { 446 Row() { 447 Text(`HelloGrandsonComponent===${this.message}`) 448 .fontSize(30) 449 .fontWeight(FontWeight.Bold) 450 } 451 } 452} 453 454@Entry 455@Component 456struct Parent { 457 @State label: string = 'Hello'; 458 build() { 459 Column() { 460 parentBuilder({paramA1: this.label}) 461 Button('Click me').onClick(() => { 462 this.label = 'ArkUI'; 463 }) 464 } 465 } 466} 467``` 468 469### \@Builder函数联合V2装饰器使用 470 471使用全局@Builder和局部@Builder在@ComponentV2修饰的自定义组件中调用,配合@ObservedV2和@Trace装饰器来监听具体值的变化,以达到触发UI刷新的功能。 472 473```ts 474@ObservedV2 475class Info { 476 @Trace name: string = ''; 477 @Trace age: number = 0; 478} 479 480@Builder 481function overBuilder(param: Info) { 482 Column() { 483 Text(`全局@Builder name :${param.name}`) 484 .fontSize(30) 485 .fontWeight(FontWeight.Bold) 486 Text(`全局@Builder age :${param.age}`) 487 .fontSize(30) 488 .fontWeight(FontWeight.Bold) 489 } 490} 491 492@ComponentV2 493struct ChildPage { 494 @Require @Param childInfo: Info; 495 build() { 496 overBuilder({name: this.childInfo.name, age: this.childInfo.age}) 497 } 498} 499 500@Entry 501@ComponentV2 502struct ParentPage { 503 info1: Info = { name: "Tom", age: 25 }; 504 @Local info2: Info = { name: "Tom", age: 25 }; 505 506 @Builder 507 privateBuilder() { 508 Column() { 509 Text(`局部@Builder name :${this.info1.name}`) 510 .fontSize(30) 511 .fontWeight(FontWeight.Bold) 512 Text(`局部@Builder age :${this.info1.age}`) 513 .fontSize(30) 514 .fontWeight(FontWeight.Bold) 515 } 516 } 517 518 build() { 519 Column() { 520 Text(`info1: ${this.info1.name} ${this.info1.age}`) // Text1 521 .fontSize(30) 522 .fontWeight(FontWeight.Bold) 523 this.privateBuilder() // 调用局部@Builder 524 Line() 525 .width('100%') 526 .height(10) 527 .backgroundColor('#000000').margin(10) 528 Text(`info2: ${this.info2.name} ${this.info2.age}`) // Text2 529 .fontSize(30) 530 .fontWeight(FontWeight.Bold) 531 overBuilder({ name: this.info2.name, age: this.info2.age}) // 调用全局@Builder 532 Line() 533 .width('100%') 534 .height(10) 535 .backgroundColor('#000000').margin(10) 536 Text(`info1: ${this.info1.name} ${this.info1.age}`) // Text1 537 .fontSize(30) 538 .fontWeight(FontWeight.Bold) 539 ChildPage({ childInfo: this.info1}) // 调用自定义组件 540 Line() 541 .width('100%') 542 .height(10) 543 .backgroundColor('#000000').margin(10) 544 Text(`info2: ${this.info2.name} ${this.info2.age}`) // Text2 545 .fontSize(30) 546 .fontWeight(FontWeight.Bold) 547 ChildPage({ childInfo: this.info2}) // 调用自定义组件 548 Line() 549 .width('100%') 550 .height(10) 551 .backgroundColor('#000000').margin(10) 552 Button("change info1&info2") 553 .onClick(() => { 554 this.info1 = { name: "Cat", age: 18}; // Text1不会刷新,原因是没有装饰器修饰监听不到值的改变。 555 this.info2 = { name: "Cat", age: 18}; // Text2会刷新,原因是有装饰器修饰,可以监听到值的改变。 556 }) 557 } 558 } 559} 560``` 561 562## 常见问题 563 564### \@Builder存在两个或者两个以上参数 565 566当参数存在两个或者两个以上的时候,就算通过对象字面量的形式传递,值的改变也不会引起UI刷新。 567 568【反例】 569 570```ts 571class GlobalTmp { 572 str_value: string = 'Hello'; 573} 574 575@Builder function overBuilder(param: GlobalTmp, num: number) { 576 Column() { 577 Text(`str_value: ${param.str_value}`) 578 Text(`num: ${num}`) 579 } 580} 581 582@Entry 583@Component 584struct Parent { 585 @State objParam: GlobalTmp = new GlobalTmp(); 586 @State num: number = 0; 587 build() { 588 Column() { 589 Text('通过调用@Builder渲染UI界面') 590 .fontSize(20) 591 // 使用了两个参数,用法错误。 592 overBuilder({str_value: this.objParam.str_value}, this.num) 593 Line() 594 .width('100%') 595 .height(10) 596 .backgroundColor('#000000').margin(10) 597 Button('点击改变参数值').onClick(() => { 598 this.objParam.str_value = 'Hello World'; 599 this.num = 1; 600 }) 601 } 602 } 603} 604``` 605 606【反例】 607 608```ts 609class GlobalTmp { 610 str_value: string = 'Hello'; 611} 612class SecondTmp { 613 num_value: number = 0; 614} 615@Builder function overBuilder(param: GlobalTmp, num: SecondTmp) { 616 Column() { 617 Text(`str_value: ${param.str_value}`) 618 Text(`num: ${num.num_value}`) 619 } 620} 621 622@Entry 623@Component 624struct Parent { 625 @State strParam: GlobalTmp = new GlobalTmp(); 626 @State numParam: SecondTmp = new SecondTmp(); 627 build() { 628 Column() { 629 Text('通过调用@Builder渲染UI界面') 630 .fontSize(20) 631 // 使用了两个参数,用法错误。 632 overBuilder({str_value: this.strParam.str_value}, {num_value: this.numParam.num_value}) 633 Line() 634 .width('100%') 635 .height(10) 636 .backgroundColor('#000000').margin(10) 637 Button('点击改变参数值').onClick(() => { 638 this.strParam.str_value = 'Hello World'; 639 this.numParam.num_value = 1; 640 }) 641 } 642 } 643} 644``` 645 646\@Builder只接受一个参数,当传入一个参数的时候,通过对象字面量的形式传递,值的改变会引起UI的刷新。 647 648【正例】 649 650```ts 651class GlobalTmp { 652 str_value: string = 'Hello'; 653 num_value: number = 0; 654} 655@Builder function overBuilder(param: GlobalTmp) { 656 Column() { 657 Text(`str_value: ${param.str_value}`) 658 Text(`num: ${param.num_value}`) 659 } 660} 661 662@Entry 663@Component 664struct Parent { 665 @State objParam: GlobalTmp = new GlobalTmp(); 666 build() { 667 Column() { 668 Text('通过调用@Builder渲染UI界面') 669 .fontSize(20) 670 overBuilder({str_value: this.objParam.str_value, num_value: this.objParam.num_value}) 671 Line() 672 .width('100%') 673 .height(10) 674 .backgroundColor('#000000').margin(10) 675 Button('点击改变参数值').onClick(() => { 676 this.objParam.str_value = 'Hello World'; 677 this.objParam.num_value = 1; 678 }) 679 } 680 } 681} 682``` 683 684### 使用@ComponentV2装饰器触发动态刷新 685 686使用按值传递的方式,在@ComponentV2装饰器修饰的自定义组件里配合使用@ObservedV2和@Trace装饰器可以实现刷新UI功能。 687 688【反例】 689 690在@ComponentV2装饰的自定义组件中,使用简单数据类型不可以触发UI的刷新。 691 692```ts 693@ObservedV2 694class ParamTmp { 695 @Trace count : number = 0; 696} 697 698@Builder 699function renderNumber(paramNum: number) { 700 Text(`paramNum : ${paramNum}`) 701 .fontSize(30) 702 .fontWeight(FontWeight.Bold) 703} 704 705@Entry 706@ComponentV2 707struct PageBuilder { 708 @Local class_value: ParamTmp = new ParamTmp(); 709 // 此处使用简单数据类型不支持刷新UI的能力。 710 @Local num_value: number = 0; 711 private progressTimer: number = -1; 712 713 aboutToAppear(): void { 714 this.progressTimer = setInterval(() => { 715 if (this.class_value.count < 100) { 716 this.class_value.count += 5; 717 this.num_value += 5; 718 } else { 719 clearInterval(this.progressTimer); 720 } 721 }, 500); 722 } 723 724 build() { 725 Column() { 726 renderNumber(this.num_value) 727 } 728 .width('100%') 729 .height('100%') 730 .padding(50) 731 } 732} 733``` 734 735【正例】 736 737在@ComponentV2装饰中,只有使用@ObservedV2修饰的ParamTmp类和@Trace修饰的count属性才可以触发UI的刷新。 738 739```ts 740@ObservedV2 741class ParamTmp { 742 @Trace count : number = 0; 743} 744 745@Builder 746function renderText(param: ParamTmp) { 747 Column() { 748 Text(`param : ${param.count}`) 749 .fontSize(20) 750 .fontWeight(FontWeight.Bold) 751 } 752} 753 754@Builder 755function renderMap(paramMap: Map<string,number>) { 756 Text(`paramMap : ${paramMap.get('name')}`) 757 .fontSize(20) 758 .fontWeight(FontWeight.Bold) 759} 760 761@Builder 762function renderSet(paramSet: Set<number>) { 763 Text(`paramSet : ${paramSet.size}`) 764 .fontSize(20) 765 .fontWeight(FontWeight.Bold) 766} 767 768@Builder 769function renderNumberArr(paramNumArr: number[]) { 770 Text(`paramNumArr : ${paramNumArr[0]}`) 771 .fontSize(20) 772 .fontWeight(FontWeight.Bold) 773} 774 775@Entry 776@ComponentV2 777struct PageBuilder { 778 @Local builderParams: ParamTmp = new ParamTmp(); 779 @Local map_value: Map<string,number> = new Map(); 780 @Local set_value: Set<number> = new Set([0]); 781 @Local numArr_value: number[] = [0]; 782 private progressTimer: number = -1; 783 784 aboutToAppear(): void { 785 this.progressTimer = setInterval(() => { 786 if (this.builderParams.count < 100) { 787 this.builderParams.count += 5; 788 this.map_value.set('name', this.builderParams.count); 789 this.set_value.add(this.builderParams.count); 790 this.numArr_value[0] = this.builderParams.count; 791 } else { 792 clearInterval(this.progressTimer); 793 } 794 }, 500); 795 } 796 797 @Builder 798 localBuilder() { 799 Column() { 800 Text(`localBuilder : ${this.builderParams.count}`) 801 .fontSize(20) 802 .fontWeight(FontWeight.Bold) 803 } 804 } 805 806 build() { 807 Column() { 808 this.localBuilder() 809 Text(`builderParams :${this.builderParams.count}`) 810 .fontSize(20) 811 .fontWeight(FontWeight.Bold) 812 renderText(this.builderParams) 813 renderText({ count: this.builderParams.count }) 814 renderMap(this.map_value) 815 renderSet(this.set_value) 816 renderNumberArr(this.numArr_value) 817 } 818 .width('100%') 819 .height('100%') 820 } 821} 822``` 823 824### 在\@Builder装饰的函数内部修改入参内容 825 826【反例】 827 828```ts 829interface Temp { 830 paramA: string; 831} 832 833@Builder function overBuilder(param: Temp) { 834 Row() { 835 Column() { 836 Button(`overBuilder === ${param.paramA}`) 837 .onClick(() => { 838 // 错误写法,不允许在@Builder装饰的函数内部修改参数值 839 param.paramA = 'Yes'; 840 }) 841 } 842 } 843} 844 845@Entry 846@Component 847struct Parent { 848 @State label: string = 'Hello'; 849 850 build() { 851 Column() { 852 overBuilder({paramA: this.label}) 853 Button('click me') 854 .onClick(() => { 855 this.label = 'ArkUI'; 856 }) 857 } 858 } 859} 860``` 861 862【正例】 863 864```ts 865interface Temp { 866 paramA: string; 867} 868 869@Builder function overBuilder(param: Temp) { 870 Row() { 871 Column() { 872 Button(`overBuilder === ${param.paramA}`) 873 } 874 } 875} 876 877@Entry 878@Component 879struct Parent { 880 @State label: string = 'Hello'; 881 882 build() { 883 Column() { 884 overBuilder({paramA: this.label}) 885 Button('click me') 886 .onClick(() => { 887 this.label = 'ArkUI'; 888 }) 889 } 890 } 891} 892```