1# ComponentContent 2 3ComponentContent表示组件内容的实体封装,其对象支持在非UI组件中创建与传递,便于开发者对弹窗类组件进行解耦封装。ComponentContent底层使用了BuilderNode,相关使用规格参考[BuilderNode](js-apis-arkui-builderNode.md)。 4 5> **说明:** 6> 7> 本模块从API version 12开始支持。后续版本的新增接口,采用上角标单独标记接口的起始版本。 8> 9> 当前不支持在预览器中使用ComponentContent。 10 11 12## 导入模块 13 14```ts 15import { ComponentContent } from '@kit.ArkUI'; 16``` 17 18## ComponentContent 19 20### constructor 21 22constructor(uiContext: UIContext, builder: WrappedBuilder\<[]>) 23 24ComponentContent的构造函数。 25 26**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 27 28**系统能力:** SystemCapability.ArkUI.ArkUI.Full 29 30**参数:** 31 32| 参数名 | 类型 | 必填 | 说明 | 33| --------- | ----------------------------------------- | ---- | ---------------------------------- | 34| uiContext | [UIContext](./js-apis-arkui-UIContext.md) | 是 | 创建对应节点时候所需要的UI上下文。 | 35| builder | [WrappedBuilder\<[]>](../../ui/state-management/arkts-wrapBuilder.md) | 是 | 封装不带参builder函数的WrappedBuilder对象。 | 36 37### constructor 38 39constructor(uiContext: UIContext, builder: WrappedBuilder\<[T]>, args: T) 40 41ComponentContent的构造函数。 42 43**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 44 45**系统能力:** SystemCapability.ArkUI.ArkUI.Full 46 47**参数:** 48 49| 参数名 | 类型 | 必填 | 说明 | 50| --------- | ----------------------------------------- | ---- | ---------------------------------- | 51| uiContext | [UIContext](./js-apis-arkui-UIContext.md) | 是 | 创建对应节点时候所需要的UI上下文。 | 52| builder | [WrappedBuilder\<[T]>](../../ui/state-management/arkts-wrapBuilder.md) | 是 | 封装带参builder函数的WrappedBuilder对象。 | 53| args | T | 是 | WrappedBuilder对象封装的builder函数的参数。 | 54 55### constructor 56 57 constructor(uiContext: UIContext, builder: WrappedBuilder\<[T]>, args: T, options: BuildOptions) 58 59ComponentContent的构造函数。 60 61**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 62 63**系统能力:** SystemCapability.ArkUI.ArkUI.Full 64 65**参数:** 66 67| 参数名 | 类型 | 必填 | 说明 | 68| --------- | ----------------------------------------- | ---- | ---------------------------------- | 69| uiContext | [UIContext](./js-apis-arkui-UIContext.md) | 是 | 创建对应节点时候所需要的UI上下文。 | 70| builder | [WrappedBuilder\<[T]>](../../ui/state-management/arkts-wrapBuilder.md) | 是 | 封装带参builder函数的WrappedBuilder对象。 | 71| args | T | 是 | WrappedBuilder对象封装的builder函数的参数。 | 72| options | [BuildOptions](./js-apis-arkui-builderNode.md#buildoptions12) | 是 | build的配置参数,判断是否支持@Builder中嵌套@Builder的行为。 | 73 74**示例:** 75``` ts 76import { ComponentContent, NodeContent, typeNode } from "@kit.ArkUI" 77 78interface ParamsInterface { 79 text: string; 80 func: Function; 81} 82 83@Builder 84function buildTextWithFunc(fun: Function) { 85 Text(fun()) 86 .fontSize(50) 87 .fontWeight(FontWeight.Bold) 88 .margin({ bottom: 36 }) 89} 90 91@Builder 92function buildText(params: ParamsInterface) { 93 Column() { 94 Text(params.text) 95 .fontSize(50) 96 .fontWeight(FontWeight.Bold) 97 .margin({ bottom: 36 }) 98 buildTextWithFunc(params.func) 99 } 100} 101 102@Entry 103@Component 104struct Index { 105 @State message: string = "HELLO" 106 private content: NodeContent = new NodeContent(); 107 108 build() { 109 Row() { 110 Column() { 111 Button('addComponentContent') 112 .onClick(() => { 113 let column = typeNode.createNode(this.getUIContext(), "Column"); 114 column.initialize(); 115 column.addComponentContent(new ComponentContent<ParamsInterface>(this.getUIContext(), 116 wrapBuilder<[ParamsInterface]>(buildText), { 117 text: this.message, func: () => { 118 return "FUNCTION" 119 } 120 }, { nestingBuilderSupported: true })) 121 this.content.addFrameNode(column); 122 }) 123 ContentSlot(this.content) 124 } 125 .id("column") 126 .width('100%') 127 .height('100%') 128 } 129 .height('100%') 130 } 131} 132 133``` 134 135### update 136 137update(args: T): void 138 139用于更新WrappedBuilder对象封装的builder函数参数,与constructor传入的参数类型保持一致。 140 141**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 142 143**系统能力:** SystemCapability.ArkUI.ArkUI.Full 144 145**参数:** 146 147| 参数名 | 类型 | 必填 | 说明 | 148| ------ | ---- | ---- | ------------------------------------------------------------ | 149| args | T | 是 | 用于更新WrappedBuilder对象封装的builder函数参数,与constructor传入的参数类型保持一致。 | 150 151**示例:** 152 153```ts 154import { ComponentContent } from "@kit.ArkUI"; 155 156class Params { 157 text: string = "" 158 constructor(text: string) { 159 this.text = text; 160 } 161} 162 163@Builder 164function buildText(params: Params) { 165 Column() { 166 Text(params.text) 167 .fontSize(50) 168 .fontWeight(FontWeight.Bold) 169 .margin({bottom: 36}) 170 }.backgroundColor('#FFF0F0F0') 171} 172 173@Entry 174@Component 175struct Index { 176 @State message: string = "hello" 177 178 build() { 179 Row() { 180 Column() { 181 Button("click me") 182 .onClick(() => { 183 let uiContext = this.getUIContext(); 184 let promptAction = uiContext.getPromptAction(); 185 let contentNode = new ComponentContent(uiContext, wrapBuilder(buildText), new Params(this.message)); 186 promptAction.openCustomDialog(contentNode); 187 188 setTimeout(() => { 189 contentNode.update(new Params("new message")); 190 }, 2000); //2秒后自动更新弹窗内容文本 191 }) 192 } 193 .width('100%') 194 .height('100%') 195 } 196 .height('100%') 197 } 198} 199``` 200 201### reuse 202 203reuse(param?: Object): void 204 205传递reuse事件到ComponentContent中的自定义组件。 206 207**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 208 209**系统能力:** SystemCapability.ArkUI.ArkUI.Full 210 211**参数:** 212 213| 参数名 | 类型 | 必填 | 说明 | 214| ------ | ------ | ---- | ------------------------------------------------------------------------ | 215| param | Object | 否 | 用于复用WrappedBuilder对象封装的builder函数参数,与constructor传入的参数类型保持一致。 | 216 217### recycle 218 219recycle(): void 220 221传递recycle事件到ComponentContent中的自定义组件。 222 223**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 224 225**系统能力:** SystemCapability.ArkUI.ArkUI.Full 226 227```ts 228import { NodeContent, typeNode, ComponentContent } from "@kit.ArkUI"; 229 230const TEST_TAG: string = "Reuse+Recycle"; 231 232class MyDataSource { 233 private dataArray: string[] = []; 234 private listener: DataChangeListener | null = null 235 236 public totalCount(): number { 237 return this.dataArray.length; 238 } 239 240 public getData(index: number) { 241 return this.dataArray[index]; 242 } 243 244 public pushData(data: string) { 245 this.dataArray.push(data); 246 } 247 248 public reloadListener(): void { 249 this.listener?.onDataReloaded(); 250 } 251 252 public registerDataChangeListener(listener: DataChangeListener): void { 253 this.listener = listener; 254 } 255 256 public unregisterDataChangeListener(): void { 257 this.listener = null; 258 } 259} 260 261class Params { 262 item: string = ''; 263 264 constructor(item: string) { 265 this.item = item; 266 } 267} 268 269@Builder 270function buildNode(param: Params = new Params("hello")) { 271 Row() { 272 Text(`C${param.item} -- `) 273 ReusableChildComponent2({ item: param.item }) //该自定义组件在ComponentContent中无法被正确复用 274 } 275} 276 277// 被回收复用的自定义组件,其状态变量会更新,而子自定义组件ReusableChildComponent3中的状态变量也会更新,但ComponentContent会阻断这一传递过程 278@Reusable 279@Component 280struct ReusableChildComponent { 281 @Prop item: string = ''; 282 @Prop switch: string = ''; 283 private content: NodeContent = new NodeContent(); 284 private componentContent: ComponentContent<Params> = new ComponentContent<Params>( 285 this.getUIContext(), 286 wrapBuilder<[Params]>(buildNode), 287 new Params(this.item), 288 { nestingBuilderSupported: true }); 289 290 aboutToAppear() { 291 let column = typeNode.createNode(this.getUIContext(), "Column"); 292 column.initialize(); 293 column.addComponentContent(this.componentContent); 294 this.content.addFrameNode(column); 295 } 296 297 aboutToRecycle(): void { 298 console.log(`${TEST_TAG} ReusableChildComponent aboutToRecycle ${this.item}`); 299 300 // 当开关为open,通过ComponentContent的reuse接口和recycle接口传递给其下的自定义组件,例如ReusableChildComponent2,完成复用 301 if (this.switch === 'open') { 302 this.componentContent.recycle(); 303 } 304 } 305 306 aboutToReuse(params: object): void { 307 console.log(`${TEST_TAG} ReusableChildComponent aboutToReuse ${JSON.stringify(params)}`); 308 309 // 当开关为open,通过ComponentContent的reuse接口和recycle接口传递给其下的自定义组件,例如ReusableChildComponent2,完成复用 310 if (this.switch === 'open') { 311 this.componentContent.reuse(params); 312 } 313 } 314 315 build() { 316 Row() { 317 Text(`A${this.item}--`) 318 ReusableChildComponent3({ item: this.item }) 319 ContentSlot(this.content) 320 } 321 } 322} 323 324@Component 325struct ReusableChildComponent2 { 326 @Prop item: string = "false"; 327 328 aboutToReuse(params: Record<string, object>) { 329 console.log(`${TEST_TAG} ReusableChildComponent2 aboutToReuse ${JSON.stringify(params)}`); 330 } 331 332 aboutToRecycle(): void { 333 console.log(`${TEST_TAG} ReusableChildComponent2 aboutToRecycle ${this.item}`); 334 } 335 336 build() { 337 Row() { 338 Text(`D${this.item}`) 339 .fontSize(20) 340 .backgroundColor(Color.Yellow) 341 .margin({ left: 10 }) 342 }.margin({ left: 10, right: 10 }) 343 } 344} 345 346@Component 347struct ReusableChildComponent3 { 348 @Prop item: string = "false"; 349 350 aboutToReuse(params: Record<string, object>) { 351 console.log(`${TEST_TAG} ReusableChildComponent3 aboutToReuse ${JSON.stringify(params)}`); 352 } 353 354 aboutToRecycle(): void { 355 console.log(`${TEST_TAG} ReusableChildComponent3 aboutToRecycle ${this.item}`); 356 } 357 358 build() { 359 Row() { 360 Text(`B${this.item}`) 361 .fontSize(20) 362 .backgroundColor(Color.Yellow) 363 .margin({ left: 10 }) 364 }.margin({ left: 10, right: 10 }) 365 } 366} 367 368 369@Entry 370@Component 371struct Index { 372 @State data: MyDataSource = new MyDataSource(); 373 374 aboutToAppear() { 375 for (let i = 0; i < 100; i++) { 376 this.data.pushData(i.toString()); 377 } 378 } 379 380 build() { 381 Column() { 382 List({ space: 3 }) { 383 LazyForEach(this.data, (item: string) => { 384 ListItem() { 385 ReusableChildComponent({ 386 item: item, 387 switch: 'open' // 将open改为close可观察到,ComponentContent不通过reuse和recycle接口传递复用时,ComponentContent内部的自定义组件的行为表现 388 }) 389 } 390 }, (item: string) => item) 391 } 392 .width('100%') 393 .height('100%') 394 } 395 } 396} 397``` 398 399### dispose 400 401dispose(): void 402 403立即释放当前ComponentContent,即ComponentContent对象与后端实体节点解除引用关系。 404 405**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 406 407**系统能力:** SystemCapability.ArkUI.ArkUI.Full 408 409**示例:** 410 411```ts 412import { BusinessError } from '@kit.BasicServicesKit'; 413import { ComponentContent } from '@kit.ArkUI'; 414 415class Params { 416 text: string = "" 417 constructor(text: string) { 418 this.text = text; 419 } 420} 421 422@Builder 423function buildText(params: Params) { 424 Column() { 425 Text(params.text) 426 .fontSize(50) 427 .fontWeight(FontWeight.Bold) 428 .margin({bottom: 36}) 429 }.backgroundColor('#FFF0F0F0') 430} 431 432@Entry 433@Component 434struct Index { 435 @State message: string = "hello" 436 437 build() { 438 Row() { 439 Column() { 440 Button("click me") 441 .onClick(() => { 442 let uiContext = this.getUIContext(); 443 let promptAction = uiContext.getPromptAction(); 444 let contentNode = new ComponentContent(uiContext, wrapBuilder(buildText), new Params(this.message)); 445 promptAction.openCustomDialog(contentNode); 446 447 setTimeout(() => { 448 promptAction.closeCustomDialog(contentNode) 449 .then(() => { 450 console.info('customdialog closed.') 451 if (contentNode !== null) { 452 contentNode.dispose(); //释放contentNode 453 } 454 }).catch((error: BusinessError) => { 455 let message = (error as BusinessError).message; 456 let code = (error as BusinessError).code; 457 console.error(`closeCustomDialog args error code is ${code}, message is ${message}`); 458 }) 459 }, 2000); //2秒后自动关闭 460 }) 461 } 462 .width('100%') 463 .height('100%') 464 } 465 .height('100%') 466 } 467} 468``` 469 470 471### updateConfiguration 472 473updateConfiguration(): void 474 475传递[系统环境变化](../apis-ability-kit/js-apis-app-ability-configuration.md)事件,触发节点的全量更新。 476 477**原子化服务API:** 从API version 12开始,该接口支持在原子化服务中使用。 478 479**系统能力:** SystemCapability.ArkUI.ArkUI.Full 480 481> **说明:** 482> 483> updateConfiguration接口功能为通知对象更新,更新所使用的系统环境由当前的系统环境变化。 484 485**示例:** 486```ts 487import { NodeController, FrameNode, ComponentContent } from '@kit.ArkUI'; 488import { AbilityConstant, Configuration, EnvironmentCallback, ConfigurationConstant } from '@kit.AbilityKit'; 489 490@Builder 491function buildText() { 492 Column() { 493 Text('Hello') 494 .fontSize(36) 495 .fontWeight(FontWeight.Bold) 496 } 497 .backgroundColor($r('sys.color.ohos_id_color_background')) 498 .width('100%') 499 .alignItems(HorizontalAlign.Center) 500 .padding(16) 501} 502 503const componentContentMap: Array<ComponentContent<[Object]>> = new Array(); 504 505class MyNodeController extends NodeController { 506 private rootNode: FrameNode | null = null; 507 508 makeNode(uiContext: UIContext): FrameNode | null { 509 return this.rootNode; 510 } 511 512 createNode(context: UIContext) { 513 this.rootNode = new FrameNode(context); 514 let component = new ComponentContent<Object>(context, wrapBuilder(buildText)); 515 componentContentMap.push(component); 516 this.rootNode.addComponentContent(component); 517 } 518 519 deleteNode() { 520 let node = componentContentMap.pop(); 521 this.rootNode?.dispose(); 522 node?.dispose(); 523 } 524} 525 526function updateColorMode() { 527 componentContentMap.forEach((value, index) => { 528 value.updateConfiguration(); 529 }) 530} 531 532@Entry 533@Component 534struct FrameNodeTypeTest { 535 private myNodeController: MyNodeController = new MyNodeController(); 536 537 aboutToAppear(): void { 538 let environmentCallback: EnvironmentCallback = { 539 onMemoryLevel: (level: AbilityConstant.MemoryLevel): void => { 540 console.log('onMemoryLevel'); 541 }, 542 onConfigurationUpdated: (config: Configuration): void => { 543 console.log('onConfigurationUpdated ' + JSON.stringify(config)); 544 updateColorMode(); 545 } 546 } 547 // 注册监听回调 548 this.getUIContext().getHostContext()?.getApplicationContext().on('environment', environmentCallback); 549 // 设置应用深浅色跟随系统 550 this.getUIContext() 551 .getHostContext()?.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET); 552 this.myNodeController.createNode(this.getUIContext()); 553 } 554 555 aboutToDisappear(): void { 556 //移除map中的引用,并将自定义节点释放 557 this.myNodeController.deleteNode(); 558 } 559 560 build() { 561 Column({ space: 16 }) { 562 NodeContainer(this.myNodeController); 563 Button('切换深色') 564 .onClick(() => { 565 this.getUIContext() 566 .getHostContext()?.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_DARK); 567 }) 568 Button('设置浅色') 569 .onClick(() => { 570 this.getUIContext() 571 .getHostContext()?.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT); 572 }) 573 } 574 } 575} 576``` 577