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`) 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 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 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