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, \@StorageLink和\@Link 建立双向绑定。允许父组件中[\@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 version 9开始,\@Link子组件从父组件初始化\@State的语法为Comp({ aLink: this.aState })。同样Comp({aLink: $aState})也支持。 | 34| 用于初始化子组件 | 允许,可用于初始化常规变量、\@State、\@Link、\@Prop、\@Provide。 | 35| 是否支持组件外访问 | 私有,只能在所属组件内访问。 | 36 37 **图1** 初始化规则图示 38 39 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 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 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