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 privateBuilder() {
334    Row() {
335      Text('局部 Builder')
336        .fontSize(30)
337        .fontWeight(FontWeight.Bold)
338    }
339  }
340
341  build() {
342    Column() {
343      List({ space: 10 }) {
344        ForEach(this.arr, (item: number) => {
345          ListItem(){
346            Text(`${item}`)
347              .width('100%')
348              .height(100)
349              .fontSize(16)
350              .textAlign(TextAlign.Center)
351              .borderRadius(10)
352              .backgroundColor(0xFFFFFF)
353          }
354            .swipeAction({
355              start: {
356                builder: overBuilder()
357              },
358              end: {
359                builder: () => { this.privateBuilder() }
360              }
361            })
362        }, (item: string) => JSON.stringify(item))
363      }
364    }
365  }
366}
367```
368
369### 多层\@Builder方法嵌套使用
370
371在\@Builder方法内调用自定义组件或者其他\@Builder方法,以实现多个\@Builder嵌套使用的场景,要想实现最里面的\@Builder动态UI刷新功能,必须要保证每层调用\@Builder的地方使用按引用传递的方式。这里的[\$$](./arkts-two-way-sync.md)也可以换成其他名称,[\$$](./arkts-two-way-sync.md)不是必须的参数形式。
372
373```ts
374class Tmp {
375  paramA1: string = '';
376}
377
378@Builder function parentBuilder($$: Tmp) {
379  Row() {
380    Column() {
381      Text(`parentBuilder===${$$.paramA1}`)
382        .fontSize(30)
383        .fontWeight(FontWeight.Bold)
384      HelloComponent({message: $$.paramA1})
385      childBuilder({paramA1: $$.paramA1})
386    }
387  }
388}
389
390@Component
391struct HelloComponent {
392  @Prop message: string = '';
393
394  build() {
395    Row() {
396      Text(`HelloComponent===${this.message}`)
397        .fontSize(30)
398        .fontWeight(FontWeight.Bold)
399    }
400  }
401}
402
403@Builder
404function childBuilder($$: Tmp) {
405  Row() {
406    Column() {
407      Text(`childBuilder===${$$.paramA1}`)
408        .fontSize(30)
409        .fontWeight(FontWeight.Bold)
410      HelloChildComponent({message: $$.paramA1})
411      grandsonBuilder({paramA1: $$.paramA1})
412    }
413  }
414}
415
416@Component
417struct HelloChildComponent {
418  @Prop message: string = '';
419  build() {
420    Row() {
421      Text(`HelloChildComponent===${this.message}`)
422        .fontSize(30)
423        .fontWeight(FontWeight.Bold)
424    }
425  }
426}
427
428@Builder function grandsonBuilder($$: Tmp) {
429  Row() {
430    Column() {
431      Text(`grandsonBuilder===${$$.paramA1}`)
432        .fontSize(30)
433        .fontWeight(FontWeight.Bold)
434      HelloGrandsonComponent({message: $$.paramA1})
435    }
436  }
437}
438
439@Component
440struct HelloGrandsonComponent {
441  @Prop message: string;
442  build() {
443    Row() {
444      Text(`HelloGrandsonComponent===${this.message}`)
445        .fontSize(30)
446        .fontWeight(FontWeight.Bold)
447    }
448  }
449}
450
451@Entry
452@Component
453struct Parent {
454  @State label: string = 'Hello';
455  build() {
456    Column() {
457      parentBuilder({paramA1: this.label})
458      Button('Click me').onClick(() => {
459        this.label = 'ArkUI';
460      })
461    }
462  }
463}
464```
465
466### \@Builder函数联合V2装饰器使用
467
468使用全局@Builder和局部@Builder在@ComponentV2修饰的自定义组件中调用,配合@ObservedV2和@Trace装饰器来监听具体值的变化,以达到触发UI刷新的功能。
469
470```ts
471@ObservedV2
472class Info {
473  @Trace name: string = '';
474  @Trace age: number = 0;
475}
476
477@Builder
478function overBuilder(param: Info) {
479  Column() {
480    Text(`全局@Builder name :${param.name}`)
481      .fontSize(30)
482      .fontWeight(FontWeight.Bold)
483    Text(`全局@Builder age :${param.age}`)
484      .fontSize(30)
485      .fontWeight(FontWeight.Bold)
486  }
487}
488
489@ComponentV2
490struct ChildPage {
491  @Require @Param childInfo: Info;
492  build() {
493    overBuilder({name: this.childInfo.name, age: this.childInfo.age})
494  }
495}
496
497@Entry
498@ComponentV2
499struct ParentPage {
500  info1: Info = { name: "Tom", age: 25 };
501  @Local info2: Info = { name: "Tom", age: 25 };
502
503  @Builder
504  privateBuilder() {
505    Column() {
506      Text(`局部@Builder name :${this.info1.name}`)
507        .fontSize(30)
508        .fontWeight(FontWeight.Bold)
509      Text(`局部@Builder age :${this.info1.age}`)
510        .fontSize(30)
511        .fontWeight(FontWeight.Bold)
512    }
513  }
514
515  build() {
516    Column() {
517      Text(`info1: ${this.info1.name}  ${this.info1.age}`) // Text1
518        .fontSize(30)
519        .fontWeight(FontWeight.Bold)
520      this.privateBuilder() // 调用局部@Builder
521      Line()
522        .width('100%')
523        .height(10)
524        .backgroundColor('#000000').margin(10)
525      Text(`info2: ${this.info2.name}  ${this.info2.age}`) // Text2
526        .fontSize(30)
527        .fontWeight(FontWeight.Bold)
528      overBuilder({ name: this.info2.name, age: this.info2.age}) // 调用全局@Builder
529      Line()
530        .width('100%')
531        .height(10)
532        .backgroundColor('#000000').margin(10)
533      Text(`info1: ${this.info1.name}  ${this.info1.age}`) // Text1
534        .fontSize(30)
535        .fontWeight(FontWeight.Bold)
536      ChildPage({ childInfo: this.info1}) // 调用自定义组件
537      Line()
538        .width('100%')
539        .height(10)
540        .backgroundColor('#000000').margin(10)
541      Text(`info2: ${this.info2.name}  ${this.info2.age}`) // Text2
542        .fontSize(30)
543        .fontWeight(FontWeight.Bold)
544      ChildPage({ childInfo: this.info2}) // 调用自定义组件
545      Line()
546        .width('100%')
547        .height(10)
548        .backgroundColor('#000000').margin(10)
549      Button("change info1&info2")
550        .onClick(() => {
551          this.info1 = { name: "Cat", age: 18}; // Text1不会刷新,原因是没有装饰器修饰监听不到值的改变。
552          this.info2 = { name: "Cat", age: 18}; // Text2会刷新,原因是有装饰器修饰,可以监听到值的改变。
553        })
554    }
555  }
556}
557```
558
559## 常见问题
560
561### \@Builder存在两个或者两个以上参数
562
563当参数存在两个或者两个以上的时候,就算通过对象字面量的形式传递,值的改变也不会引起UI刷新。
564
565【反例】
566
567```ts
568class GlobalTmp {
569  str_value: string = 'Hello';
570}
571
572@Builder function overBuilder(param: GlobalTmp, num: number) {
573  Column() {
574    Text(`str_value: ${param.str_value}`)
575    Text(`num: ${num}`)
576  }
577}
578
579@Entry
580@Component
581struct Parent {
582  @State objParam: GlobalTmp = new GlobalTmp();
583  @State num: number = 0;
584  build() {
585    Column() {
586      Text('通过调用@Builder渲染UI界面')
587        .fontSize(20)
588      // 使用了两个参数,用法错误。
589      overBuilder({str_value: this.objParam.str_value}, this.num)
590      Line()
591        .width('100%')
592        .height(10)
593        .backgroundColor('#000000').margin(10)
594      Button('点击改变参数值').onClick(() => {
595        this.objParam.str_value = 'Hello World';
596        this.num = 1;
597      })
598    }
599  }
600}
601```
602
603【反例】
604
605```ts
606class GlobalTmp {
607  str_value: string = 'Hello';
608}
609class SecondTmp {
610  num_value: number = 0;
611}
612@Builder function overBuilder(param: GlobalTmp, num: SecondTmp) {
613  Column() {
614    Text(`str_value: ${param.str_value}`)
615    Text(`num: ${num.num_value}`)
616  }
617}
618
619@Entry
620@Component
621struct Parent {
622  @State strParam: GlobalTmp = new GlobalTmp();
623  @State numParam: SecondTmp = new SecondTmp();
624  build() {
625    Column() {
626      Text('通过调用@Builder渲染UI界面')
627        .fontSize(20)
628      // 使用了两个参数,用法错误。
629      overBuilder({str_value: this.strParam.str_value}, {num_value: this.numParam.num_value})
630      Line()
631        .width('100%')
632        .height(10)
633        .backgroundColor('#000000').margin(10)
634      Button('点击改变参数值').onClick(() => {
635        this.strParam.str_value = 'Hello World';
636        this.numParam.num_value = 1;
637      })
638    }
639  }
640}
641```
642
643\@Builder只接受一个参数,当传入一个参数的时候,通过对象字面量的形式传递,值的改变会引起UI的刷新。
644
645【正例】
646
647```ts
648class GlobalTmp {
649  str_value: string = 'Hello';
650  num_value: number = 0;
651}
652@Builder function overBuilder(param: GlobalTmp) {
653  Column() {
654    Text(`str_value: ${param.str_value}`)
655    Text(`num: ${param.num_value}`)
656  }
657}
658
659@Entry
660@Component
661struct Parent {
662  @State objParam: GlobalTmp = new GlobalTmp();
663  build() {
664    Column() {
665      Text('通过调用@Builder渲染UI界面')
666        .fontSize(20)
667      overBuilder({str_value: this.objParam.str_value, num_value: this.objParam.num_value})
668      Line()
669        .width('100%')
670        .height(10)
671        .backgroundColor('#000000').margin(10)
672      Button('点击改变参数值').onClick(() => {
673        this.objParam.str_value = 'Hello World';
674        this.objParam.num_value = 1;
675      })
676    }
677  }
678}
679```
680
681### 使用@ComponentV2装饰器触发动态刷新
682
683使用按值传递的方式,在@ComponentV2装饰器修饰的自定义组件里配合使用@ObservedV2和@Trace装饰器可以实现刷新UI功能。
684
685【反例】
686
687在@ComponentV2装饰的自定义组件中,使用简单数据类型不可以触发UI的刷新。
688
689```ts
690@ObservedV2
691class ParamTmp {
692  @Trace count : number = 0;
693}
694
695@Builder
696function renderNumber(paramNum: number) {
697  Text(`paramNum : ${paramNum}`)
698    .fontSize(30)
699    .fontWeight(FontWeight.Bold)
700}
701
702@Entry
703@ComponentV2
704struct PageBuilder {
705  @Local class_value: ParamTmp = new ParamTmp();
706  // 此处使用简单数据类型不支持刷新UI的能力。
707  @Local num_value: number = 0;
708  private progressTimer: number = -1;
709
710  aboutToAppear(): void {
711    this.progressTimer = setInterval(() => {
712      if (this.class_value.count < 100) {
713        this.class_value.count += 5;
714        this.num_value += 5;
715      } else {
716        clearInterval(this.progressTimer);
717      }
718    }, 500);
719  }
720
721  build() {
722    Column() {
723      renderNumber(this.num_value)
724    }
725    .width('100%')
726    .height('100%')
727    .padding(50)
728  }
729}
730```
731
732【正例】
733
734在@ComponentV2装饰中,只有使用@ObservedV2修饰的ParamTmp类和@Trace修饰的count属性才可以触发UI的刷新。
735
736```ts
737@ObservedV2
738class ParamTmp {
739  @Trace count : number = 0;
740}
741
742@Builder
743function renderText(param: ParamTmp) {
744  Column() {
745    Text(`param : ${param.count}`)
746      .fontSize(20)
747      .fontWeight(FontWeight.Bold)
748  }
749}
750
751@Builder
752function renderMap(paramMap: Map<string,number>) {
753  Text(`paramMap : ${paramMap.get('name')}`)
754    .fontSize(20)
755    .fontWeight(FontWeight.Bold)
756}
757
758@Builder
759function renderSet(paramSet: Set<number>) {
760  Text(`paramSet : ${paramSet.size}`)
761    .fontSize(20)
762    .fontWeight(FontWeight.Bold)
763}
764
765@Builder
766function renderNumberArr(paramNumArr: number[]) {
767  Text(`paramNumArr : ${paramNumArr[0]}`)
768    .fontSize(20)
769    .fontWeight(FontWeight.Bold)
770}
771
772@Entry
773@ComponentV2
774struct PageBuilder {
775  @Local builderParams: ParamTmp = new ParamTmp();
776  @Local map_value: Map<string,number> = new Map();
777  @Local set_value: Set<number> = new Set([0]);
778  @Local numArr_value: number[] = [0];
779  private progressTimer: number = -1;
780
781  aboutToAppear(): void {
782    this.progressTimer = setInterval(() => {
783      if (this.builderParams.count < 100) {
784        this.builderParams.count += 5;
785        this.map_value.set('name', this.builderParams.count);
786        this.set_value.add(this.builderParams.count);
787        this.numArr_value[0] = this.builderParams.count;
788      } else {
789        clearInterval(this.progressTimer);
790      }
791    }, 500);
792  }
793
794  @Builder
795  localBuilder() {
796    Column() {
797      Text(`localBuilder : ${this.builderParams.count}`)
798        .fontSize(20)
799        .fontWeight(FontWeight.Bold)
800    }
801  }
802
803  build() {
804    Column() {
805      this.localBuilder()
806      Text(`builderParams :${this.builderParams.count}`)
807        .fontSize(20)
808        .fontWeight(FontWeight.Bold)
809      renderText(this.builderParams)
810      renderText({ count: this.builderParams.count })
811      renderMap(this.map_value)
812      renderSet(this.set_value)
813      renderNumberArr(this.numArr_value)
814    }
815    .width('100%')
816    .height('100%')
817  }
818}
819```
820
821### 在\@Builder装饰的函数内部修改入参内容
822
823【反例】
824
825```ts
826interface Temp {
827  paramA: string;
828}
829
830@Builder function overBuilder(param: Temp) {
831  Row() {
832    Column() {
833      Button(`overBuilder === ${param.paramA}`)
834        .onClick(() => {
835          // 错误写法,不允许在@Builder装饰的函数内部修改参数值
836          param.paramA = 'Yes';
837      })
838    }
839  }
840}
841
842@Entry
843@Component
844struct Parent {
845  @State label: string = 'Hello';
846
847  build() {
848    Column() {
849      overBuilder({paramA: this.label})
850      Button('click me')
851        .onClick(() => {
852          this.label = 'ArkUI';
853        })
854    }
855  }
856}
857```
858
859【正例】
860
861```ts
862interface Temp {
863  paramA: string;
864}
865
866@Builder function overBuilder(param: Temp) {
867  Row() {
868    Column() {
869      Button(`overBuilder === ${param.paramA}`)
870    }
871  }
872}
873
874@Entry
875@Component
876struct Parent {
877  @State label: string = 'Hello';
878
879  build() {
880    Column() {
881      overBuilder({paramA: this.label})
882      Button('click me')
883        .onClick(() => {
884          this.label = 'ArkUI';
885        })
886    }
887  }
888}
889```