• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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```