1# \@Link装饰器:父子双向同步
2
3
4子组件中被\@Link装饰的变量与其父组件中对应的数据源建立双向数据绑定。
5
6在阅读\@Link文档前,建议开发者首先了解[\@State](./arkts-state.md)的基本用法。
7
8> **说明:**
9>
10> 从API version 9开始,该装饰器支持在ArkTS卡片中使用。
11>
12> 从API version 11开始,该装饰器支持在原子化服务中使用。
13
14## 概述
15
16\@Link装饰的变量与其父组件中的数据源共享相同的值。
17
18
19## 装饰器使用规则说明
20
21| \@Link变量装饰器                                             | 说明                                                         |
22| ------------------------------------------------------------ | ------------------------------------------------------------ |
23| 装饰器参数                                                   | 无                                                           |
24| 同步类型                                                     | 双向同步。<br/>父组件中的状态变量可以与子组件\@Link建立双向同步,当其中一方改变时,另外一方能够感知到变化。 |
25| 允许装饰的变量类型                                           | Object、class、string、number、boolean、enum类型,以及这些类型的数组。<br/>支持Date类型。<br/>API11及以上支持Map、Set类型。<br/>支持ArkUI框架定义的联合类型Length、ResourceStr、ResourceColor类型。<br/>类型必须被指定,且和双向绑定状态变量的类型相同。<br/>支持类型的场景请参考[观察变化](#观察变化)。<br/>不支持any。<br/>API11及以上支持上述支持类型的联合类型,比如string \| number, string \| undefined 或者 ClassA \| null,示例见[Link支持联合类型实例](#link支持联合类型实例)。 <br/>**注意**<br/>当使用undefined和null的时候,建议显式指定类型,遵循TypeScript类型校验,比如:`@Link a : string \| undefined`。 |
26| 被装饰变量的初始值                                           | 无,禁止本地初始化。                                         |
27
28
29## 变量的传递/访问规则说明
30
31| 传递/访问      | 说明                                       |
32| ---------- | ---------------------------------------- |
33| 从父组件初始化和更新 | 必选。与父组件\@State,&nbsp;\@StorageLink和\@Link&nbsp;建立双向绑定。允许父组件中[\@State](./arkts-state.md)、\@Link、[\@Prop](./arkts-prop.md)、[\@Provide](./arkts-provide-and-consume.md)、[\@Consume](./arkts-provide-and-consume.md)、[\@ObjectLink](./arkts-observed-and-objectlink.md)、[\@StorageLink](./arkts-appstorage.md#storagelink)、[\@StorageProp](./arkts-appstorage.md#storageprop)、[\@LocalStorageLink](./arkts-localstorage.md#localstoragelink)和[\@LocalStorageProp](./arkts-localstorage.md#localstorageprop)装饰变量初始化子组件\@Link。<br/>从API&nbsp;version&nbsp;9开始,\@Link子组件从父组件初始化\@State的语法为Comp({&nbsp;aLink:&nbsp;this.aState&nbsp;})。同样Comp({aLink:&nbsp;$aState})也支持。 |
34| 用于初始化子组件   | 允许,可用于初始化常规变量、\@State、\@Link、\@Prop、\@Provide。 |
35| 是否支持组件外访问  | 私有,只能在所属组件内访问。                           |
36
37  **图1** 初始化规则图示  
38
39![zh-cn_image_0000001502092556](figures/zh-cn_image_0000001502092556.png)
40
41
42## 观察变化和行为表现
43
44
45### 观察变化
46
47- 当装饰的数据类型为boolean、string、number类型时,可以同步观察到数值的变化,示例请参考[简单类型和类对象类型的@Link](#简单类型和类对象类型的link)。
48
49- 当装饰的数据类型为class或者Object时,可以观察到赋值和属性赋值的变化,即Object.keys(observedObject)返回的所有属性,示例请参考[简单类型和类对象类型的@Link](#简单类型和类对象类型的link)。
50
51- 当装饰的对象是array时,可以观察到数组添加、删除、更新数组单元的变化,示例请参考[数组类型的@Link](#数组类型的link)。
52
53- 当装饰的对象是Date时,可以观察到Date整体的赋值,同时可通过调用Date的接口`setFullYear`, `setMonth`, `setDate`, `setHours`, `setMinutes`, `setSeconds`, `setMilliseconds`, `setTime`, `setUTCFullYear`, `setUTCMonth`, `setUTCDate`, `setUTCHours`, `setUTCMinutes`, `setUTCSeconds`, `setUTCMilliseconds` 更新Date的属性。
54
55```ts
56@Component
57struct DateComponent {
58  @Link selectedDate: Date;
59
60  build() {
61    Column() {
62      Button(`child increase the year by 1`).onClick(() => {
63        this.selectedDate.setFullYear(this.selectedDate.getFullYear() + 1)
64      })
65      Button('child update the new date')
66        .margin(10)
67        .onClick(() => {
68          this.selectedDate = new Date('2023-09-09')
69        })
70      DatePicker({
71        start: new Date('1970-1-1'),
72        end: new Date('2100-1-1'),
73        selected: this.selectedDate
74      })
75    }
76
77  }
78}
79
80@Entry
81@Component
82struct ParentComponent {
83  @State parentSelectedDate: Date = new Date('2021-08-08');
84
85  build() {
86    Column() {
87      Button('parent increase the month by 1')
88        .margin(10)
89        .onClick(() => {
90          this.parentSelectedDate.setMonth(this.parentSelectedDate.getMonth() + 1)
91        })
92      Button('parent update the new date')
93        .margin(10)
94        .onClick(() => {
95          this.parentSelectedDate = new Date('2023-07-07')
96        })
97      DatePicker({
98        start: new Date('1970-1-1'),
99        end: new Date('2100-1-1'),
100        selected: this.parentSelectedDate
101      })
102
103      DateComponent({ selectedDate:this.parentSelectedDate })
104    }
105  }
106}
107```
108
109- 当装饰的变量是Map时,可以观察到Map整体的赋值,同时可通过调用Map的接口`set`, `clear`, `delete` 更新Map的值。详见[装饰Map类型变量](#装饰map类型变量)。
110
111- 当装饰的变量是Set时,可以观察到Set整体的赋值,同时可通过调用Set的接口`add`, `clear`, `delete` 更新Set的值。详见[装饰Set类型变量](#装饰set类型变量)。
112
113### 框架行为
114
115\@Link装饰的变量和其所属的自定义组件共享生命周期。
116
117为了了解\@Link变量初始化和更新机制,有必要先了解父组件和拥有\@Link变量的子组件的关系,初始渲染和双向更新的流程(以父组件为\@State为例)。
118
1191. 初始渲染:执行父组件的build()函数后将创建子组件的新实例。初始化过程如下:
120   1. 必须指定父组件中的\@State变量,用于初始化子组件的\@Link变量。子组件的\@Link变量值与其父组件的数据源变量保持同步(双向数据同步)。
121   2. 父组件的\@State状态变量包装类通过构造函数传给子组件,子组件的\@Link包装类拿到父组件的\@State的状态变量后,将当前\@Link包装类this指针注册给父组件的\@State变量。
122
1232. \@Link的数据源的更新:即父组件中状态变量更新,引起相关子组件的\@Link的更新。处理步骤:
124   1. 通过初始渲染的步骤可知,子组件\@Link包装类把当前this指针注册给父组件。父组件\@State变量变更后,会遍历更新所有依赖它的系统组件(elementid)和状态变量(比如\@Link包装类)。
125   2. 通知\@Link包装类更新后,子组件中所有依赖\@Link状态变量的系统组件(elementId)都会被通知更新。以此实现父组件对子组件的状态数据同步。
126
1273. \@Link的更新:当子组件中\@Link更新后,处理步骤如下(以父组件为\@State为例):
128   1. \@Link更新后,调用父组件的\@State包装类的set方法,将更新后的数值同步回父组件。
129   2. 子组件\@Link和父组件\@State分别遍历依赖的系统组件,进行对应的UI的更新。以此实现子组件\@Link同步回父组件\@State。
130
131
132## 限制条件
133
1341. \@Link装饰器不能在[\@Entry](./arkts-create-custom-components.md#自定义组件的基本结构)装饰的自定义组件中使用。
135
1362. \@Link装饰的变量禁止本地初始化,否则编译期会报错。
137
138```ts
139// 错误写法,编译报错
140@Link count: number = 10;
141
142// 正确写法
143@Link count: number;
144```
145
1463. \@Link装饰的变量的类型要和数据源类型保持一致,否则框架会抛出运行时错误。
147
148【反例】
149
150```ts
151class Info {
152  info: string = 'Hello';
153}
154
155class Cousin {
156  name: string = 'Hello';
157}
158
159@Component
160struct Child {
161  // 错误写法,@Link与@State数据源类型不一致
162  @Link test: Cousin;
163
164  build() {
165    Text(this.test.name)
166  }
167}
168
169@Entry
170@Component
171struct LinkExample {
172  @State info: Info = new Info();
173
174  build() {
175    Column() {
176      // 错误写法,@Link与@State数据源类型不一致
177      Child({test: new Cousin()})
178    }
179  }
180}
181```
182
183【正例】
184
185```ts
186class Info {
187  info: string = 'Hello';
188}
189
190@Component
191struct Child {
192  // 正确写法
193  @Link test: Info;
194
195  build() {
196    Text(this.test.info)
197  }
198}
199
200@Entry
201@Component
202struct LinkExample {
203  @State info: Info = new Info();
204
205  build() {
206    Column() {
207      // 正确写法
208      Child({test: this.info})
209    }
210  }
211}
212```
213
2144. \@Link装饰的变量仅能被状态变量初始化,不能用常量初始化,编译期会有warn告警,运行时会抛出is not callable运行时错误。
215
216【反例】
217
218```ts
219class Info {
220  info: string = 'Hello';
221}
222
223@Component
224struct Child {
225  @Link msg: string;
226  @Link info: string;
227
228  build() {
229    Text(this.msg + this.info)
230  }
231}
232
233@Entry
234@Component
235struct LinkExample {
236  @State message: string = 'Hello';
237  @State info: Info = new Info();
238
239  build() {
240    Column() {
241      // 错误写法,常规变量不能初始化@Link
242      Child({msg: 'World', info: this.info.info})
243    }
244  }
245}
246```
247
248【正例】
249
250```ts
251class Info {
252  info: string = 'Hello';
253}
254
255@Component
256struct Child {
257  @Link msg: string;
258  @Link info: Info;
259
260  build() {
261    Text(this.msg + this.info.info)
262  }
263}
264
265@Entry
266@Component
267struct LinkExample {
268  @State message: string = 'Hello';
269  @State info: Info = new Info();
270
271  build() {
272    Column() {
273      // 正确写法
274      Child({msg: this.message, info: this.info})
275    }
276  }
277}
278```
279
2805. \@Link不支持装饰Function类型的变量,框架会抛出运行时错误。
281
282
283## 使用场景
284
285
286### 简单类型和类对象类型的\@Link
287
288以下示例中,点击父组件ShufflingContainer中的“Parent View: Set yellowButton”和“Parent View: Set GreenButton”,可以从父组件将变化同步给子组件。
289
290  1.点击子组件GreenButton和YellowButton中的Button,子组件会发生相应变化,将变化同步给父组件。因为@Link是双向同步,会将变化同步给@State。
291
292  2.当点击父组件ShufflingContainer中的Button时,@State变化,也会同步给@Link,子组件也会发生对应的刷新。
293
294```ts
295class GreenButtonState {
296  width: number = 0;
297
298  constructor(width: number) {
299    this.width = width;
300  }
301}
302
303@Component
304struct GreenButton {
305  @Link greenButtonState: GreenButtonState;
306
307  build() {
308    Button('Green Button')
309      .width(this.greenButtonState.width)
310      .height(40)
311      .backgroundColor('#64bb5c')
312      .fontColor('#FFFFFF,90%')
313      .onClick(() => {
314        if (this.greenButtonState.width < 700) {
315          // 更新class的属性,变化可以被观察到同步回父组件
316          this.greenButtonState.width += 60;
317        } else {
318          // 更新class,变化可以被观察到同步回父组件
319          this.greenButtonState = new GreenButtonState(180);
320        }
321      })
322  }
323}
324
325@Component
326struct YellowButton {
327  @Link yellowButtonState: number;
328
329  build() {
330    Button('Yellow Button')
331      .width(this.yellowButtonState)
332      .height(40)
333      .backgroundColor('#f7ce00')
334      .fontColor('#FFFFFF,90%')
335      .onClick(() => {
336        // 子组件的简单类型可以同步回父组件
337        this.yellowButtonState += 40.0;
338      })
339  }
340}
341
342@Entry
343@Component
344struct ShufflingContainer {
345  @State greenButtonState: GreenButtonState = new GreenButtonState(180);
346  @State yellowButtonProp: number = 180;
347
348  build() {
349    Column() {
350      Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center }) {
351        // 简单类型从父组件@State向子组件@Link数据同步
352        Button('Parent View: Set yellowButton')
353          .width(312)
354          .height(40)
355          .margin(12)
356          .fontColor('#FFFFFF,90%')
357          .onClick(() => {
358            this.yellowButtonProp = (this.yellowButtonProp < 700) ? this.yellowButtonProp + 40 : 100;
359          })
360        // class类型从父组件@State向子组件@Link数据同步
361        Button('Parent View: Set GreenButton')
362          .width(312)
363          .height(40)
364          .margin(12)
365          .fontColor('#FFFFFF,90%')
366          .onClick(() => {
367            this.greenButtonState.width = (this.greenButtonState.width < 700) ? this.greenButtonState.width + 100 : 100;
368          })
369        // class类型初始化@Link
370        GreenButton({ greenButtonState: $greenButtonState }).margin(12)
371        // 简单类型初始化@Link
372        YellowButton({ yellowButtonState: $yellowButtonProp }).margin(12)
373      }
374    }
375  }
376}
377```
378
379![Video-link-UsageScenario-one](figures/Video-link-UsageScenario-one.gif)
380
381### 数组类型的\@Link
382
383
384```ts
385@Component
386struct Child {
387  @Link items: number[];
388
389  build() {
390    Column() {
391      Button(`Button1: push`)
392        .margin(12)
393        .width(312)
394        .height(40)
395        .fontColor('#FFFFFF,90%')
396        .onClick(() => {
397          this.items.push(this.items.length + 1);
398        })
399      Button(`Button2: replace whole item`)
400        .margin(12)
401        .width(312)
402        .height(40)
403        .fontColor('#FFFFFF,90%')
404        .onClick(() => {
405          this.items = [100, 200, 300];
406        })
407    }
408  }
409}
410
411@Entry
412@Component
413struct Parent {
414  @State arr: number[] = [1, 2, 3];
415
416  build() {
417    Column() {
418      Child({ items: $arr })
419        .margin(12)
420      ForEach(this.arr,
421        (item: number) => {
422          Button(`${item}`)
423            .margin(12)
424            .width(312)
425            .height(40)
426            .backgroundColor('#11a2a2a2')
427            .fontColor('#e6000000')
428        },
429        (item: ForEachInterface) => item.toString()
430      )
431    }
432  }
433}
434```
435
436![Video-link-UsageScenario-two](figures/Video-link-UsageScenario-two.gif)
437
438上文所述,ArkUI框架可以观察到数组元素的添加,删除和替换。在该示例中\@State和\@Link的类型是相同的number[],不允许将\@Link定义成number类型(\@Link item : number),并在父组件中用\@State数组中每个数据项创建子组件。如果要使用这个场景,可以参考[\@Prop](arkts-prop.md)和[\@Observed](./arkts-observed-and-objectlink.md)。
439
440### 装饰Map类型变量
441
442> **说明:**
443>
444> 从API version 11开始,\@Link支持Map类型。
445
446在下面的示例中,value类型为Map\<number, string\>,点击Button改变message的值,视图会随之刷新。
447
448```ts
449@Component
450struct Child {
451  @Link value: Map<number, string>
452
453  build() {
454    Column() {
455      ForEach(Array.from(this.value.entries()), (item: [number, string]) => {
456        Text(`${item[0]}`).fontSize(30)
457        Text(`${item[1]}`).fontSize(30)
458        Divider()
459      })
460      Button('child init map').onClick(() => {
461        this.value = new Map([[0, "a"], [1, "b"], [3, "c"]])
462      })
463      Button('child set new one').onClick(() => {
464        this.value.set(4, "d")
465      })
466      Button('child clear').onClick(() => {
467        this.value.clear()
468      })
469      Button('child replace the first one').onClick(() => {
470        this.value.set(0, "aa")
471      })
472      Button('child delete the first one').onClick(() => {
473        this.value.delete(0)
474      })
475    }
476  }
477}
478
479
480@Entry
481@Component
482struct MapSample {
483  @State message: Map<number, string> = new Map([[0, "a"], [1, "b"], [3, "c"]])
484
485  build() {
486    Row() {
487      Column() {
488        Child({ value: this.message })
489      }
490      .width('100%')
491    }
492    .height('100%')
493  }
494}
495```
496
497### 装饰Set类型变量
498
499> **说明:**
500>
501> 从API version 11开始,\@Link支持Set类型。
502
503在下面的示例中,message类型为Set\<number\>,点击Button改变message的值,视图会随之刷新。
504
505```ts
506@Component
507struct Child {
508  @Link message: Set<number>
509
510  build() {
511    Column() {
512      ForEach(Array.from(this.message.entries()), (item: [number, string]) => {
513        Text(`${item[0]}`).fontSize(30)
514        Divider()
515      })
516      Button('init set').onClick(() => {
517        this.message = new Set([0, 1, 2, 3, 4])
518      })
519      Button('set new one').onClick(() => {
520        this.message.add(5)
521      })
522      Button('clear').onClick(() => {
523        this.message.clear()
524      })
525      Button('delete the first one').onClick(() => {
526        this.message.delete(0)
527      })
528    }
529    .width('100%')
530  }
531}
532
533
534@Entry
535@Component
536struct SetSample {
537  @State message: Set<number> = new Set([0, 1, 2, 3, 4])
538
539  build() {
540    Row() {
541      Column() {
542        Child({ message: this.message })
543      }
544      .width('100%')
545    }
546    .height('100%')
547  }
548}
549```
550
551### 使用双向同步机制更改本地其他变量
552
553使用[\@Watch](./arkts-watch.md)可以在双向同步时,更改本地变量。
554
555下面的示例中,在\@Link的\@Watch里面修改了一个\@State装饰的变量sourceNumber,实现了父子组件间的变量同步。但是\@State装饰的变量memberMessage在本地修改又不会影响到父组件中的变量改变。
556
557```ts
558@Entry
559@Component
560struct Parent {
561  @State sourceNumber: number = 0;
562
563  build() {
564    Column() {
565      Text(`父组件的sourceNumber:` + this.sourceNumber)
566      Child({ sourceNumber: this.sourceNumber })
567      Button('父组件更改sourceNumber')
568        .onClick(() => {
569          this.sourceNumber++;
570        })
571    }
572    .width('100%')
573    .height('100%')
574  }
575}
576
577@Component
578struct Child {
579  @State memberMessage: string = 'Hello World';
580  @Link @Watch('onSourceChange') sourceNumber: number;
581
582  onSourceChange() {
583    this.memberMessage = this.sourceNumber.toString();
584  }
585
586  build() {
587    Column() {
588      Text(this.memberMessage)
589      Text(`子组件的sourceNumber:` + this.sourceNumber.toString())
590      Button('子组件更改memberMessage')
591        .onClick(() => {
592          this.memberMessage = 'Hello memberMessage';
593        })
594    }
595  }
596}
597```
598
599## Link支持联合类型实例
600
601@Link支持联合类型和undefined和null,在下面的示例中,name类型为string | undefined,点击父组件Index中的Button改变name的属性或者类型,Child中也会对应刷新。
602
603```ts
604@Component
605struct Child {
606  @Link name: string | undefined
607
608  build() {
609    Column() {
610
611      Button('Child change name to Bob')
612        .onClick(() => {
613          this.name = "Bob"
614        })
615
616      Button('Child change name to undefined')
617        .onClick(() => {
618          this.name = undefined
619        })
620
621    }.width('100%')
622  }
623}
624
625@Entry
626@Component
627struct Index {
628  @State name: string | undefined = "mary"
629
630  build() {
631    Column() {
632      Text(`The name is  ${this.name}`).fontSize(30)
633
634      Child({ name: this.name })
635
636      Button('Parents change name to Peter')
637        .onClick(() => {
638          this.name = "Peter"
639        })
640
641      Button('Parents change name to undefined')
642        .onClick(() => {
643          this.name = undefined
644        })
645    }
646  }
647}
648```
649
650## 常见问题
651
652### \@Link装饰状态变量类型错误
653
654在子组件中使用\@Link装饰状态变量需要保证该变量与数据源类型完全相同,且该数据源需为被诸如\@State等装饰器装饰的状态变量。
655
656【反例】
657
658```ts
659@Observed
660class Info {
661  public age: number = 0;
662
663  constructor(age: number) {
664    this.age = age;
665  }
666}
667
668@Component
669struct LinkChild {
670  @Link testNum: number;
671
672  build() {
673    Text(`LinkChild testNum ${this.testNum}`)
674  }
675}
676
677@Entry
678@Component
679struct Parent {
680  @State info: Info = new Info(1);
681
682  build() {
683    Column() {
684      Text(`Parent testNum ${this.info.age}`)
685        .onClick(() => {
686          this.info.age += 1;
687        })
688      // @Link装饰的变量需要和数据源@State类型一致
689      LinkChild({ testNum: this.info.age })
690    }
691  }
692}
693```
694
695\@Link testNum: number从父组件的LinkChild({testNum:this.info.age})初始化。\@Link的数据源必须是装饰器装饰的状态变量,简而言之,\@Link装饰的数据必须和数据源类型相同,比如\@Link: T和\@State : T。所以,这里应该改为\@Link testNum: Info,从父组件初始化的方式为LinkChild({testNum: this.info})
696
697【正例】
698
699```ts
700@Observed
701class Info {
702  public age: number = 0;
703
704  constructor(age: number) {
705    this.age = age;
706  }
707}
708
709@Component
710struct LinkChild {
711  @Link testNum: Info;
712
713  build() {
714    Text(`LinkChild testNum ${this.testNum?.age}`)
715      .onClick(() => {
716        this.testNum.age += 1;
717      })
718  }
719}
720
721@Entry
722@Component
723struct Parent {
724  @State info: Info = new Info(1);
725
726  build() {
727    Column() {
728      Text(`Parent testNum ${this.info.age}`)
729        .onClick(() => {
730          this.info.age += 1;
731        })
732      // @Link装饰的变量需要和数据源@State类型一致
733      LinkChild({ testNum: this.info })
734    }
735  }
736}
737```
738
739### 使用a.b(this.object)形式调用,不会触发UI刷新
740
741在build方法内,当@Link装饰的变量是Object类型、且通过a.b(this.object)形式调用时,b方法内传入的是this.object的原生对象,修改其属性,无法触发UI刷新。如下例中,通过静态方法Score.changeScore1或者this.changeScore2修改Child组件中的this.score.value时,UI不会刷新。
742
743【反例】
744
745```ts
746class Score {
747  value: number;
748  constructor(value: number) {
749    this.value = value;
750  }
751
752  static changeScore1(score:Score) {
753    score.value += 1;
754  }
755}
756
757@Entry
758@Component
759struct Parent {
760  @State score: Score = new Score(1);
761
762  build() {
763    Column({space:8}) {
764      Text(`The value in Parent is ${this.score.value}.`)
765        .fontSize(30)
766        .fontColor(Color.Red)
767      Child({ score: this.score })
768    }
769    .width('100%')
770    .height('100%')
771  }
772}
773
774@Component
775struct Child {
776  @Link score: Score;
777
778  changeScore2(score:Score) {
779    score.value += 2;
780  }
781
782  build() {
783    Column({space:8}) {
784      Text(`The value in Child is ${this.score.value}.`)
785        .fontSize(30)
786      Button(`changeScore1`)
787        .onClick(()=>{
788          // 通过静态方法调用,无法触发UI刷新
789          Score.changeScore1(this.score);
790        })
791      Button(`changeScore2`)
792        .onClick(()=>{
793          // 使用this通过自定义组件内部方法调用,无法触发UI刷新
794          this.changeScore2(this.score);
795        })
796    }
797  }
798}
799```
800
801可以通过如下先赋值、再调用新赋值的变量的方式为this.score加上Proxy代理,实现UI刷新。
802
803【正例】
804
805```ts
806class Score {
807  value: number;
808  constructor(value: number) {
809    this.value = value;
810  }
811
812  static changeScore1(score:Score) {
813    score.value += 1;
814  }
815}
816
817@Entry
818@Component
819struct Parent {
820  @State score: Score = new Score(1);
821
822  build() {
823    Column({space:8}) {
824      Text(`The value in Parent is ${this.score.value}.`)
825        .fontSize(30)
826        .fontColor(Color.Red)
827      Child({ score: this.score })
828    }
829    .width('100%')
830    .height('100%')
831  }
832}
833
834@Component
835struct Child {
836  @Link score: Score;
837
838  changeScore2(score:Score) {
839    score.value += 2;
840  }
841
842  build() {
843    Column({space:8}) {
844      Text(`The value in Child is ${this.score.value}.`)
845        .fontSize(30)
846      Button(`changeScore1`)
847        .onClick(()=>{
848          // 通过赋值添加 Proxy 代理
849          let score1 = this.score;
850          Score.changeScore1(score1);
851        })
852      Button(`changeScore2`)
853        .onClick(()=>{
854          // 通过赋值添加 Proxy 代理
855          let score2 = this.score;
856          this.changeScore2(score2);
857        })
858    }
859  }
860}
861```
862
863<!--no_check-->
864