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