1# ComponentContent 2<!--Kit: ArkUI--> 3<!--Subsystem: ArkUI--> 4<!--Owner: @liyi0309--> 5<!--Designer: @liyi0309--> 6<!--Tester: @lxl007--> 7<!--Adviser: @HelloCrease--> 8 9ComponentContent表示组件内容的实体封装,其对象支持在非UI组件中创建与传递,便于开发者对弹窗类组件进行解耦封装。其底层使用了BuilderNode,具体使用规格参考[BuilderNode](js-apis-arkui-builderNode.md)。 10 11> **说明:** 12> 13> 本模块从API version 12开始支持。后续版本的新增接口,采用上角标单独标记接口的起始版本。 14> 15> 当前不支持在预览器中使用ComponentContent。 16 17 18## 导入模块 19 20```ts 21import { ComponentContent } from '@kit.ArkUI'; 22``` 23 24## ComponentContent 25 26继承自[Content](js-apis-arkui-Content.md#content-1)。 27 28**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 29 30**系统能力:** SystemCapability.ArkUI.ArkUI.Full 31 32### constructor 33 34constructor(uiContext: UIContext, builder: WrappedBuilder\<[]>) 35 36ComponentContent的构造函数。 37 38**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 39 40**系统能力:** SystemCapability.ArkUI.ArkUI.Full 41 42**参数:** 43 44| 参数名 | 类型 | 必填 | 说明 | 45| --------- | ----------------------------------------- | ---- | ---------------------------------- | 46| uiContext | [UIContext](./arkts-apis-uicontext-uicontext.md) | 是 | 创建对应节点时所需要的UI上下文。 | 47| builder | [WrappedBuilder\<[]>](../../ui/state-management/arkts-wrapBuilder.md) | 是 | 封装不带参builder函数的WrappedBuilder对象。 | 48 49### constructor 50 51constructor(uiContext: UIContext, builder: WrappedBuilder\<[T]>, args: T) 52 53ComponentContent的构造函数。 54 55**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 56 57**系统能力:** SystemCapability.ArkUI.ArkUI.Full 58 59**参数:** 60 61| 参数名 | 类型 | 必填 | 说明 | 62| --------- | ----------------------------------------- | ---- | ---------------------------------- | 63| uiContext | [UIContext](./arkts-apis-uicontext-uicontext.md) | 是 | 创建对应节点时候所需要的UI上下文。 | 64| builder | [WrappedBuilder\<[T]>](../../ui/state-management/arkts-wrapBuilder.md) | 是 | 封装带参builder函数的WrappedBuilder对象。 | 65| args | T | 是 | WrappedBuilder对象封装的builder函数的参数。 | 66 67### constructor 68 69 constructor(uiContext: UIContext, builder: WrappedBuilder\<[T]>, args: T, options: BuildOptions) 70 71ComponentContent的构造函数。 72 73**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 74 75**系统能力:** SystemCapability.ArkUI.ArkUI.Full 76 77**参数:** 78 79| 参数名 | 类型 | 必填 | 说明 | 80| --------- | ----------------------------------------- | ---- | ---------------------------------- | 81| uiContext | [UIContext](./arkts-apis-uicontext-uicontext.md) | 是 | 创建对应节点时候所需要的UI上下文。 | 82| builder | [WrappedBuilder\<[T]>](../../ui/state-management/arkts-wrapBuilder.md) | 是 | 封装带参builder函数的WrappedBuilder对象。 | 83| args | T | 是 | WrappedBuilder对象封装的builder函数的参数。 | 84| options | [BuildOptions](./js-apis-arkui-builderNode.md#buildoptions12) | 是 | build的配置参数,判断是否支持@Builder中嵌套@Builder的行为。 | 85 86**示例:** 87``` ts 88import { ComponentContent, NodeContent, typeNode } from "@kit.ArkUI"; 89 90interface ParamsInterface { 91 text: string; 92 func: Function; 93} 94 95@Builder 96function buildTextWithFunc(fun: Function) { 97 Text(fun()) 98 .fontSize(50) 99 .fontWeight(FontWeight.Bold) 100 .margin({ bottom: 36 }) 101} 102 103@Builder 104function buildText(params: ParamsInterface) { 105 Column() { 106 Text(params.text) 107 .fontSize(50) 108 .fontWeight(FontWeight.Bold) 109 .margin({ bottom: 36 }) 110 buildTextWithFunc(params.func) 111 } 112} 113 114@Entry 115@Component 116struct Index { 117 @State message: string = "HELLO"; 118 private content: NodeContent = new NodeContent(); 119 120 build() { 121 Row() { 122 Column() { 123 Button('addComponentContent') 124 .onClick(() => { 125 let column = typeNode.createNode(this.getUIContext(), "Column"); 126 column.initialize(); 127 column.addComponentContent(new ComponentContent<ParamsInterface>(this.getUIContext(), 128 wrapBuilder<[ParamsInterface]>(buildText), { 129 text: this.message, func: () => { 130 return "FUNCTION" 131 } 132 }, { nestingBuilderSupported: true })); 133 this.content.addFrameNode(column); 134 }) 135 ContentSlot(this.content) 136 } 137 .id("column") 138 .width('100%') 139 .height('100%') 140 } 141 .height('100%') 142 } 143} 144 145``` 146 147### update 148 149update(args: T): void 150 151用于更新[WrappedBuilder](../../ui/state-management/arkts-wrapBuilder.md)对象封装的builder函数参数,与constructor传入的参数类型保持一致。 152 153**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 154 155**系统能力:** SystemCapability.ArkUI.ArkUI.Full 156 157**参数:** 158 159| 参数名 | 类型 | 必填 | 说明 | 160| ------ | ---- | ---- | ------------------------------------------------------------ | 161| args | T | 是 | 用于更新[WrappedBuilder](../../ui/state-management/arkts-wrapBuilder.md)对象封装的builder函数参数,与constructor传入的参数类型保持一致。 | 162 163**示例:** 164 165```ts 166import { ComponentContent } from "@kit.ArkUI"; 167 168class Params { 169 text: string = ""; 170 constructor(text: string) { 171 this.text = text; 172 } 173} 174 175@Builder 176function buildText(params: Params) { 177 Column() { 178 Text(params.text) 179 .fontSize(50) 180 .fontWeight(FontWeight.Bold) 181 .margin({bottom: 36}) 182 }.backgroundColor('#FFF0F0F0') 183} 184 185@Entry 186@Component 187struct Index { 188 @State message: string = "hello"; 189 190 build() { 191 Row() { 192 Column() { 193 Button("click me") 194 .onClick(() => { 195 let uiContext = this.getUIContext(); 196 let promptAction = uiContext.getPromptAction(); 197 let contentNode = new ComponentContent(uiContext, wrapBuilder(buildText), new Params(this.message)); 198 promptAction.openCustomDialog(contentNode); 199 200 setTimeout(() => { 201 contentNode.update(new Params("new message")); 202 }, 2000); //2秒后自动更新弹窗内容文本 203 }) 204 } 205 .width('100%') 206 .height('100%') 207 } 208 .height('100%') 209 } 210} 211``` 212 213### reuse 214 215reuse(param?: Object): void 216 217触发ComponentContent中的自定义组件的复用。组件复用请参见[@Reusable装饰器:组件复用](../../ui/state-management/arkts-reusable.md)。关于ComponentContent的解绑场景请参见[解除实体节点引用关系](../../ui/arkts-user-defined-arktsNode-builderNode.md#解除实体节点引用关系)。 218 219**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 220 221**系统能力:** SystemCapability.ArkUI.ArkUI.Full 222 223**参数:** 224 225| 参数名 | 类型 | 必填 | 说明 | 226| ------ | ------ | ---- | ------------------------------------------------------------------------ | 227| param | Object | 否 | 用于复用WrappedBuilder对象封装的builder函数参数,与constructor传入的参数类型保持一致。 | 228 229### recycle 230 231recycle(): void 232 233- 触发ComponentContent中自定义组件的回收。自定义组件的回收是组件复用机制中的环节,具体信息请参见[@Reusable装饰器:组件复用](../../ui/state-management/arkts-reusable.md)。 234- ComponentContent通过reuse和recycle完成其内外自定义组件之间的复用事件传递,具体使用场景请参见[BuilderNode调用reuse和recycle接口实现节点复用能力](../../ui/arkts-user-defined-arktsNode-builderNode.md#buildernode调用reuse和recycle接口实现节点复用能力)。 235 236**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 237 238**系统能力:** SystemCapability.ArkUI.ArkUI.Full 239 240```ts 241import { NodeContent, typeNode, ComponentContent } from "@kit.ArkUI"; 242 243const TEST_TAG: string = "Reuse+Recycle"; 244 245class MyDataSource { 246 private dataArray: string[] = []; 247 private listener: DataChangeListener | null = null; 248 249 public totalCount(): number { 250 return this.dataArray.length; 251 } 252 253 public getData(index: number) { 254 return this.dataArray[index]; 255 } 256 257 public pushData(data: string) { 258 this.dataArray.push(data); 259 } 260 261 public reloadListener(): void { 262 this.listener?.onDataReloaded(); 263 } 264 265 public registerDataChangeListener(listener: DataChangeListener): void { 266 this.listener = listener; 267 } 268 269 public unregisterDataChangeListener(): void { 270 this.listener = null; 271 } 272} 273 274class Params { 275 item: string = ''; 276 277 constructor(item: string) { 278 this.item = item; 279 } 280} 281 282@Builder 283function buildNode(param: Params = new Params("hello")) { 284 Row() { 285 Text(`C${param.item} -- `) 286 ReusableChildComponent2({ item: param.item }) //该自定义组件在ComponentContent中无法被正确复用 287 } 288} 289 290// 被回收复用的自定义组件,其状态变量会更新,而子自定义组件ReusableChildComponent3中的状态变量也会更新,但ComponentContent会阻断这一传递过程 291@Reusable 292@Component 293struct ReusableChildComponent { 294 @Prop item: string = ''; 295 @Prop switch: string = ''; 296 private content: NodeContent = new NodeContent(); 297 private componentContent: ComponentContent<Params> = new ComponentContent<Params>( 298 this.getUIContext(), 299 wrapBuilder<[Params]>(buildNode), 300 new Params(this.item), 301 { nestingBuilderSupported: true }); 302 303 aboutToAppear() { 304 let column = typeNode.createNode(this.getUIContext(), "Column"); 305 column.initialize(); 306 column.addComponentContent(this.componentContent); 307 this.content.addFrameNode(column); 308 } 309 310 aboutToRecycle(): void { 311 console.info(`${TEST_TAG} ReusableChildComponent aboutToRecycle ${this.item}`); 312 313 // 当开关为open,通过ComponentContent的reuse接口和recycle接口传递给其下的自定义组件,例如ReusableChildComponent2,完成复用 314 if (this.switch === 'open') { 315 this.componentContent.recycle(); 316 } 317 } 318 319 aboutToReuse(params: object): void { 320 console.info(`${TEST_TAG} ReusableChildComponent aboutToReuse ${JSON.stringify(params)}`); 321 322 // 当开关为open,通过ComponentContent的reuse接口和recycle接口传递给其下的自定义组件,例如ReusableChildComponent2,完成复用 323 if (this.switch === 'open') { 324 this.componentContent.reuse(params); 325 } 326 } 327 328 build() { 329 Row() { 330 Text(`A${this.item}--`) 331 ReusableChildComponent3({ item: this.item }) 332 ContentSlot(this.content) 333 } 334 } 335} 336 337@Component 338struct ReusableChildComponent2 { 339 @Prop item: string = "false"; 340 341 aboutToReuse(params: Record<string, object>) { 342 console.info(`${TEST_TAG} ReusableChildComponent2 aboutToReuse ${JSON.stringify(params)}`); 343 } 344 345 aboutToRecycle(): void { 346 console.info(`${TEST_TAG} ReusableChildComponent2 aboutToRecycle ${this.item}`); 347 } 348 349 build() { 350 Row() { 351 Text(`D${this.item}`) 352 .fontSize(20) 353 .backgroundColor(Color.Yellow) 354 .margin({ left: 10 }) 355 }.margin({ left: 10, right: 10 }) 356 } 357} 358 359@Component 360struct ReusableChildComponent3 { 361 @Prop item: string = "false"; 362 363 aboutToReuse(params: Record<string, object>) { 364 console.info(`${TEST_TAG} ReusableChildComponent3 aboutToReuse ${JSON.stringify(params)}`); 365 } 366 367 aboutToRecycle(): void { 368 console.info(`${TEST_TAG} ReusableChildComponent3 aboutToRecycle ${this.item}`); 369 } 370 371 build() { 372 Row() { 373 Text(`B${this.item}`) 374 .fontSize(20) 375 .backgroundColor(Color.Yellow) 376 .margin({ left: 10 }) 377 }.margin({ left: 10, right: 10 }) 378 } 379} 380 381 382@Entry 383@Component 384struct Index { 385 @State data: MyDataSource = new MyDataSource(); 386 387 aboutToAppear() { 388 for (let i = 0; i < 100; i++) { 389 this.data.pushData(i.toString()); 390 } 391 } 392 393 build() { 394 Column() { 395 List({ space: 3 }) { 396 LazyForEach(this.data, (item: string) => { 397 ListItem() { 398 ReusableChildComponent({ 399 item: item, 400 switch: 'open' // 将open改为close可观察到,ComponentContent不通过reuse和recycle接口传递复用时,ComponentContent内部的自定义组件的行为表现 401 }) 402 } 403 }, (item: string) => item) 404 } 405 .width('100%') 406 .height('100%') 407 } 408 } 409} 410``` 411 412### dispose 413 414dispose(): void 415 416立即释放当前ComponentContent对象对[基本概念:实体节点](../../ui/arkts-user-defined-node.md#基本概念)的引用关系。关于ComponentContent的解绑场景请参见[解除实体节点引用关系](../../ui/arkts-user-defined-arktsNode-builderNode.md#解除实体节点引用关系)。 417 418**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 419 420**系统能力:** SystemCapability.ArkUI.ArkUI.Full 421 422> **说明:** 423> 424> 当ComponentContent对象调用dispose之后,会与后端实体节点解除引用关系。若前端对象ComponentContent无法释放,容易导致内存泄漏。建议在不再需要操作该ComponentContent对象时,开发者主动调用dispose释放后端节点,以减少引用关系的复杂性,降低内存泄漏的风险。 425 426**示例:** 427 428```ts 429import { BusinessError } from '@kit.BasicServicesKit'; 430import { ComponentContent } from '@kit.ArkUI'; 431 432class Params { 433 text: string = ""; 434 constructor(text: string) { 435 this.text = text; 436 } 437} 438 439@Builder 440function buildText(params: Params) { 441 Column() { 442 Text(params.text) 443 .fontSize(50) 444 .fontWeight(FontWeight.Bold) 445 .margin({ bottom: 36 }) 446 }.backgroundColor('#FFF0F0F0') 447} 448 449@Entry 450@Component 451struct Index { 452 @State message: string = "hello"; 453 454 build() { 455 Row() { 456 Column() { 457 Button("click me") 458 .onClick(() => { 459 let uiContext = this.getUIContext(); 460 let promptAction = uiContext.getPromptAction(); 461 let contentNode = new ComponentContent(uiContext, wrapBuilder(buildText), new Params(this.message)); 462 promptAction.openCustomDialog(contentNode); 463 464 setTimeout(() => { 465 promptAction.closeCustomDialog(contentNode) 466 .then(() => { 467 console.info('customDialog closed.'); 468 if (contentNode !== null) { 469 contentNode.dispose(); //释放contentNode 470 } 471 }).catch((error: BusinessError) => { 472 let message = (error as BusinessError).message; 473 let code = (error as BusinessError).code; 474 console.error(`closeCustomDialog args error code is ${code}, message is ${message}`); 475 }) 476 }, 2000); //2秒后自动关闭 477 }) 478 } 479 .width('100%') 480 .height('100%') 481 } 482 .height('100%') 483 } 484} 485``` 486 487 488### updateConfiguration 489 490updateConfiguration(): void 491 492传递[系统环境变化](../apis-ability-kit/js-apis-app-ability-configuration.md)事件,触发节点的全量更新。 493 494**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 495 496**系统能力:** SystemCapability.ArkUI.ArkUI.Full 497 498> **说明:** 499> 500> updateConfiguration接口用于通知对象更新当前的系统环境变化。 501 502**示例:** 503```ts 504import { NodeController, FrameNode, ComponentContent, UIContext, FrameCallback } from '@kit.ArkUI'; 505import { AbilityConstant, Configuration, EnvironmentCallback, ConfigurationConstant } from '@kit.AbilityKit'; 506 507@Builder 508function buildText() { 509 Column() { 510 Text('Hello') 511 .fontSize(36) 512 .fontWeight(FontWeight.Bold) 513 } 514 .backgroundColor($r('sys.color.ohos_id_color_background')) 515 .width('100%') 516 .alignItems(HorizontalAlign.Center) 517 .padding(16) 518} 519 520const componentContentMap: Array<ComponentContent<[Object]>> = new Array(); 521 522class MyNodeController extends NodeController { 523 private rootNode: FrameNode | null = null; 524 525 makeNode(uiContext: UIContext): FrameNode | null { 526 return this.rootNode; 527 } 528 529 createNode(context: UIContext) { 530 this.rootNode = new FrameNode(context); 531 let component = new ComponentContent<Object>(context, wrapBuilder(buildText)); 532 componentContentMap.push(component); 533 this.rootNode.addComponentContent(component); 534 } 535 536 deleteNode() { 537 let node = componentContentMap.pop(); 538 this.rootNode?.dispose(); 539 node?.dispose(); 540 } 541} 542 543class MyFrameCallback extends FrameCallback { 544 onFrame() { 545 updateColorMode(); 546 } 547} 548 549function updateColorMode() { 550 componentContentMap.forEach((value, index) => { 551 value.updateConfiguration(); 552 }) 553} 554 555@Entry 556@Component 557struct FrameNodeTypeTest { 558 private myNodeController: MyNodeController = new MyNodeController(); 559 560 aboutToAppear(): void { 561 let environmentCallback: EnvironmentCallback = { 562 onMemoryLevel: (level: AbilityConstant.MemoryLevel): void => { 563 console.info('onMemoryLevel'); 564 }, 565 onConfigurationUpdated: (config: Configuration): void => { 566 console.info(`onConfigurationUpdated ${config}`); 567 this.getUIContext()?.postFrameCallback(new MyFrameCallback()); 568 } 569 } 570 // 注册监听回调 571 this.getUIContext().getHostContext()?.getApplicationContext().on('environment', environmentCallback); 572 // 设置应用深浅色跟随系统 573 this.getUIContext() 574 .getHostContext()?.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET); 575 this.myNodeController.createNode(this.getUIContext()); 576 } 577 578 aboutToDisappear(): void { 579 //移除map中的引用,并将自定义节点释放 580 this.myNodeController.deleteNode(); 581 } 582 583 build() { 584 Column({ space: 16 }) { 585 NodeContainer(this.myNodeController); 586 Button('切换深色') 587 .onClick(() => { 588 this.getUIContext() 589 .getHostContext()?.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_DARK); 590 }) 591 Button('设置浅色') 592 .onClick(() => { 593 this.getUIContext() 594 .getHostContext()?.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT); 595 }) 596 } 597 } 598} 599``` 600 601### isDisposed<sup>20+</sup> 602 603isDisposed(): boolean 604 605查询当前ComponentContent对象是否已解除与后端实体节点的引用关系。前端节点均绑定有相应的后端实体节点,当节点调用dispose接口解除绑定后,再次调用接口可能会出现crash、返回默认值的情况。由于业务需求,可能存在节点在dispose后仍被调用接口的情况。为此,提供此接口以供开发者在操作节点前检查其有效性,避免潜在风险。 606 607 608**原子化服务API:** 从API version 20开始,该接口支持在原子化服务中使用。 609 610**系统能力:** SystemCapability.ArkUI.ArkUI.Full 611 612**返回值:** 613 614| 类型 | 说明 | 615| ------- | ------------------ | 616| boolean | 后端实体节点是否解除引用。true为节点已与后端实体节点解除引用,false为节点未与后端实体节点解除引用。 617 618**示例:** 619 620```ts 621import { BusinessError } from '@kit.BasicServicesKit'; 622import { ComponentContent } from '@kit.ArkUI'; 623 624class Params { 625 text: string = ""; 626 constructor(text: string) { 627 this.text = text; 628 } 629} 630 631@Builder 632function buildText(params: Params) { 633 Column() { 634 Text(params.text) 635 .fontSize(50) 636 .fontWeight(FontWeight.Bold) 637 .margin({ bottom: 36 }) 638 }.backgroundColor('#FFF0F0F0') 639} 640 641@Entry 642@Component 643struct Index { 644 @State message: string = "hello"; 645 @State beforeDispose: string = '' 646 @State afterDispose: string = '' 647 648 build() { 649 Row() { 650 Column() { 651 Button("click me") 652 .onClick(() => { 653 let uiContext = this.getUIContext(); 654 let promptAction = uiContext.getPromptAction(); 655 let contentNode = new ComponentContent(uiContext, wrapBuilder(buildText), new Params(this.message)); 656 promptAction.openCustomDialog(contentNode); 657 658 setTimeout(() => { 659 promptAction.closeCustomDialog(contentNode) 660 .then(() => { 661 console.info('customDialog closed.'); 662 if (contentNode !== null) { 663 this.beforeDispose = contentNode.isDisposed() ? 'before dispose componentContent isDisposed is true' : 'before dispose componentContent isDisposed is false'; 664 contentNode.dispose(); //释放contentNode 665 this.afterDispose = contentNode.isDisposed() ? 'after dispose componentContent isDisposed is true' : 'after dispose componentContent isDisposed is false'; 666 } 667 }).catch((error: BusinessError) => { 668 let message = (error as BusinessError).message; 669 let code = (error as BusinessError).code; 670 console.error(`closeCustomDialog args error code is ${code}, message is ${message}`); 671 }) 672 }, 1000); //1秒后自动关闭 673 }) 674 Text(this.beforeDispose) 675 .fontSize(25) 676 .margin({ top: 10, bottom: 10 }) 677 Text(this.afterDispose) 678 .fontSize(25) 679 } 680 .width('100%') 681 .height('100%') 682 } 683 .height('100%') 684 } 685} 686``` 687 688 689 690### inheritFreezeOptions<sup>20+</sup> 691 692inheritFreezeOptions(enabled: boolean): void 693 694查询当前ComponentContent对象是否设置为继承父组件中自定义组件的冻结策略。如果设置继承状态为false,则ComponentContent对象的冻结策略为false。在这种情况下,节点在不活跃状态下不会被冻结。 695 696 697**原子化服务API:** 从API version 20开始,该接口支持在原子化服务中使用。 698 699**系统能力:** SystemCapability.ArkUI.ArkUI.Full 700 701**参数:** 702 703| 参数名 | 类型 | 必填 | 说明 | 704| ------ | ------ | ---- | ------------------------------------------------------------------------ | 705| enabled | boolean | 是 | ComponentContent对象是否设置为继承父组件中自定义组件的冻结策略。true为继承父组件中自定义组件的冻结策略,false为不继承父组件中自定义组件的冻结策略。 | 706 707**示例:** 708 709```ts 710 711import { ComponentContent, FrameNode, NodeController } from '@kit.ArkUI'; 712 713class Params { 714 count: number = 0; 715 716 constructor(count: number) { 717 this.count = count; 718 } 719} 720 721@Builder // builder组件 722function buildText(params: Params) { 723 724 Column() { 725 TextBuilder({ message: params.count }) 726 } 727} 728 729class TextNodeController extends NodeController { 730 private rootNode: FrameNode | null = null; 731 private contentNode: ComponentContent<Params> | null = null; 732 private count: number = 0; 733 734 makeNode(context: UIContext): FrameNode | null { 735 this.rootNode = new FrameNode(context); 736 this.contentNode = new ComponentContent(context, wrapBuilder(buildText), new Params(this.count)); // 通过buildText创建ComponentContent 737 this.contentNode.inheritFreezeOptions(true); // 设置ComponentContent的冻结继承状态为True 738 if (this.rootNode !== null) { 739 this.rootNode.addComponentContent(this.contentNode); // 将ComponentContent上树 740 } 741 return this.rootNode; 742 } 743 744 update(): void { 745 if (this.contentNode !== null) { 746 this.count += 1; 747 this.contentNode.update(new Params(this.count)); // 更新ComponentContent中的数据,可以触发Log 748 } 749 } 750} 751 752const textNodeController: TextNodeController = new TextNodeController(); 753 754@Entry 755@Component 756struct MyNavigationTestStack { 757 @Provide('pageInfo') pageInfo: NavPathStack = new NavPathStack(); 758 @State message: number = 0; 759 @State logNumber: number = 0; 760 761 @Builder 762 PageMap(name: string) { 763 if (name === 'pageOne') { 764 pageOneStack({ message: this.message, logNumber: this.logNumber }) 765 } else if (name === 'pageTwo') { 766 pageTwoStack({ message: this.message, logNumber: this.logNumber }) 767 } 768 } 769 770 build() { 771 Column() { 772 Button('update ComponentContent') // 点击更新ComponentContent 773 .onClick(() => { 774 textNodeController.update(); 775 }) 776 Navigation(this.pageInfo) { 777 Column() { 778 Button('Next Page', { stateEffect: true, type: ButtonType.Capsule }) 779 .width('80%') 780 .height(40) 781 .margin(20) 782 .onClick(() => { 783 this.pageInfo.pushPath({ name: 'pageOne' }); // 将name指定的NavDestination页面信息入栈 784 }) 785 } 786 }.title('NavIndex') 787 .navDestination(this.PageMap) 788 .mode(NavigationMode.Stack) 789 } 790 } 791} 792 793@Component 794struct pageOneStack { // 页面一 795 @Consume('pageInfo') pageInfo: NavPathStack; 796 @State index: number = 1; 797 @Link message: number; 798 @Link logNumber: number; 799 800 build() { 801 NavDestination() { 802 Column() { 803 NavigationContentMsgStack({ message: this.message, index: this.index, logNumber: this.logNumber }) 804 Button('Next Page', { stateEffect: true, type: ButtonType.Capsule }) // 切换至页面二 805 .width('80%') 806 .height(40) 807 .margin(20) 808 .onClick(() => { 809 this.pageInfo.pushPathByName('pageTwo', null); 810 }) 811 Button('Back Page', { stateEffect: true, type: ButtonType.Capsule }) // 返回主页面 812 .width('80%') 813 .height(40) 814 .margin(20) 815 .onClick(() => { 816 this.pageInfo.pop(); 817 }) 818 }.width('100%').height('100%') 819 }.title('pageOne') 820 .onBackPressed(() => { 821 this.pageInfo.pop(); 822 return true; 823 }) 824 } 825} 826 827@Component 828struct pageTwoStack { // 页面二 829 @Consume('pageInfo') pageInfo: NavPathStack; 830 @State index: number = 2; 831 @Link message: number; 832 @Link logNumber: number; 833 834 build() { 835 NavDestination() { 836 Column() { 837 NavigationContentMsgStack({ message: this.message, index: this.index, logNumber: this.logNumber }) 838 Text('BuilderNode处于冻结') 839 .fontWeight(FontWeight.Bold) 840 .margin({ top: 48, bottom: 48 }) 841 Button('Back Page', { stateEffect: true, type: ButtonType.Capsule }) // 返回至页面一 842 .width('80%') 843 .height(40) 844 .margin(20) 845 .onClick(() => { 846 this.pageInfo.pop(); 847 }) 848 }.width('100%').height('100%') 849 }.title('pageTwo') 850 .onBackPressed(() => { 851 this.pageInfo.pop(); 852 return true; 853 }) 854 } 855} 856 857@Component({ freezeWhenInactive: true }) // 设置冻结策略为不活跃冻结 858struct NavigationContentMsgStack { 859 @Link message: number; 860 @Link index: number; 861 @Link logNumber: number; 862 863 build() { 864 Column() { 865 if (this.index === 1) { 866 NodeContainer(textNodeController) 867 } 868 } 869 } 870} 871 872@Component({ freezeWhenInactive: true }) // 设置冻结策略为不活跃冻结 873struct TextBuilder { 874 @Prop @Watch("info") message: number = 0; 875 876 info() { 877 console.info(`freeze-test TextBuilder message callback ${this.message}`); // 根据message内容变化来打印日志来判断是否冻结 878 } 879 880 build() { 881 Row() { 882 Column() { 883 Text(`文本更新次数: ${this.message}`) 884 .fontWeight(FontWeight.Bold) 885 .margin({ top: 48, bottom: 48 }) 886 } 887 } 888 } 889} 890``` 891 892 893