1e41f4b71Sopenharmony_ci# Precisely Controlling Render Scope 2e41f4b71Sopenharmony_ci 3e41f4b71Sopenharmony_ciIn development of complex pages, precisely controlling the component render scope is especially important to speed up applications. 4e41f4b71Sopenharmony_ci 5e41f4b71Sopenharmony_ciThis document exemplifies why and how the component render scope may be precisely controlled. For starters, you need to understand the re-render mechanism with state management. 6e41f4b71Sopenharmony_ci 7e41f4b71Sopenharmony_ci```ts 8e41f4b71Sopenharmony_ci@Observed 9e41f4b71Sopenharmony_ciclass ClassA { 10e41f4b71Sopenharmony_ci prop1: number = 0; 11e41f4b71Sopenharmony_ci prop2: string = "This is Prop2"; 12e41f4b71Sopenharmony_ci} 13e41f4b71Sopenharmony_ci@Component 14e41f4b71Sopenharmony_cistruct CompA { 15e41f4b71Sopenharmony_ci @ObjectLink a: ClassA; 16e41f4b71Sopenharmony_ci private sizeFont: number = 30; // the private variable does not invoke rendering 17e41f4b71Sopenharmony_ci private isRenderText() : number { 18e41f4b71Sopenharmony_ci this.sizeFont++; // the change of sizeFont will not invoke rendering, but showing that the function is called 19e41f4b71Sopenharmony_ci console.log("Text prop2 is rendered"); 20e41f4b71Sopenharmony_ci return this.sizeFont; 21e41f4b71Sopenharmony_ci } 22e41f4b71Sopenharmony_ci build() { 23e41f4b71Sopenharmony_ci Column() { 24e41f4b71Sopenharmony_ci Text(this.a.prop2) // when this.a.prop2 changes, it will invoke Text rerendering 25e41f4b71Sopenharmony_ci .fontSize(this.isRenderText()) // If the <Text> renders, the function isRenderText will be called. 26e41f4b71Sopenharmony_ci } 27e41f4b71Sopenharmony_ci } 28e41f4b71Sopenharmony_ci} 29e41f4b71Sopenharmony_ci@Entry 30e41f4b71Sopenharmony_ci@Component 31e41f4b71Sopenharmony_cistruct Page { 32e41f4b71Sopenharmony_ci @State a: ClassA = new ClassA(); 33e41f4b71Sopenharmony_ci build() { 34e41f4b71Sopenharmony_ci Row() { 35e41f4b71Sopenharmony_ci Column() { 36e41f4b71Sopenharmony_ci Text("Prop1: " + this.a.prop1) 37e41f4b71Sopenharmony_ci .fontSize(50) 38e41f4b71Sopenharmony_ci .margin({ bottom: 20 }) 39e41f4b71Sopenharmony_ci CompA({a: this.a}) 40e41f4b71Sopenharmony_ci Button("Change prop1") 41e41f4b71Sopenharmony_ci .width(200) 42e41f4b71Sopenharmony_ci .margin({ top: 20 }) 43e41f4b71Sopenharmony_ci .onClick(() => { 44e41f4b71Sopenharmony_ci this.a.prop1 = this.a.prop1 + 1 ; 45e41f4b71Sopenharmony_ci }) 46e41f4b71Sopenharmony_ci } 47e41f4b71Sopenharmony_ci .width('100%') 48e41f4b71Sopenharmony_ci } 49e41f4b71Sopenharmony_ci .width('100%') 50e41f4b71Sopenharmony_ci .height('100%') 51e41f4b71Sopenharmony_ci } 52e41f4b71Sopenharmony_ci} 53e41f4b71Sopenharmony_ci``` 54e41f4b71Sopenharmony_ci 55e41f4b71Sopenharmony_ciIn the preceding example, when the value of **prop1** changes at the click of the button, although the components in **CompA** do not use **prop1**, you can still observe that the **\<Text>** component associated with **prop2** is re-rendered – reflected by the component's enlarged font size and the console log of "Text prop2 is rendered." This indicates that, when a property (**prop1** in this example) of an @Observed decorated class object is changed, all components associated with any property of this object are re-rendered at once, even though these components may not directly use the changed property (i.e., the **\<Text>** component using **prop** in this example). In this case, invisible, redundant re-renders occur. When a large number of components are involved in redundant re-renders, the render performance is greatly affected. 56e41f4b71Sopenharmony_ci 57e41f4b71Sopenharmony_ciThe following figure shows the code running. 58e41f4b71Sopenharmony_ci 59e41f4b71Sopenharmony_ci 60e41f4b71Sopenharmony_ci 61e41f4b71Sopenharmony_ciThe following is a typical example of redundant re-renders. 62e41f4b71Sopenharmony_ci 63e41f4b71Sopenharmony_ci```ts 64e41f4b71Sopenharmony_ci@Observed 65e41f4b71Sopenharmony_ciclass UIStyle { 66e41f4b71Sopenharmony_ci translateX: number = 0; 67e41f4b71Sopenharmony_ci translateY: number = 0; 68e41f4b71Sopenharmony_ci scaleX: number = 0.3; 69e41f4b71Sopenharmony_ci scaleY: number = 0.3; 70e41f4b71Sopenharmony_ci width: number = 336; 71e41f4b71Sopenharmony_ci height: number = 178; 72e41f4b71Sopenharmony_ci posX: number = 10; 73e41f4b71Sopenharmony_ci posY: number = 50; 74e41f4b71Sopenharmony_ci alpha: number = 0.5; 75e41f4b71Sopenharmony_ci borderRadius: number = 24; 76e41f4b71Sopenharmony_ci imageWidth: number = 78; 77e41f4b71Sopenharmony_ci imageHeight: number = 78; 78e41f4b71Sopenharmony_ci translateImageX: number = 0; 79e41f4b71Sopenharmony_ci translateImageY: number = 0; 80e41f4b71Sopenharmony_ci fontSize: number = 20; 81e41f4b71Sopenharmony_ci} 82e41f4b71Sopenharmony_ci@Component 83e41f4b71Sopenharmony_cistruct SpecialImage { 84e41f4b71Sopenharmony_ci @ObjectLink uiStyle: UIStyle; 85e41f4b71Sopenharmony_ci private isRenderSpecialImage() : number { // Function to show whether the component is rendered. 86e41f4b71Sopenharmony_ci console.log("SpecialImage is rendered"); 87e41f4b71Sopenharmony_ci return 1; 88e41f4b71Sopenharmony_ci } 89e41f4b71Sopenharmony_ci build() { 90e41f4b71Sopenharmony_ci Image($r('app.media.icon')) 91e41f4b71Sopenharmony_ci .width(this.uiStyle.imageWidth) 92e41f4b71Sopenharmony_ci .height(this.uiStyle.imageHeight) 93e41f4b71Sopenharmony_ci .margin({ top: 20 }) 94e41f4b71Sopenharmony_ci .translate({ 95e41f4b71Sopenharmony_ci x: this.uiStyle.translateImageX, 96e41f4b71Sopenharmony_ci y: this.uiStyle.translateImageY 97e41f4b71Sopenharmony_ci }) 98e41f4b71Sopenharmony_ci .opacity(this.isRenderSpecialImage()) // If the <Image> is rendered, it will call the function. 99e41f4b71Sopenharmony_ci } 100e41f4b71Sopenharmony_ci} 101e41f4b71Sopenharmony_ci@Component 102e41f4b71Sopenharmony_cistruct CompA { 103e41f4b71Sopenharmony_ci @ObjectLink uiStyle: UIStyle 104e41f4b71Sopenharmony_ci // The following functions are used to show whether the component is called to be rendered. 105e41f4b71Sopenharmony_ci private isRenderColumn() : number { 106e41f4b71Sopenharmony_ci console.log("Column is rendered"); 107e41f4b71Sopenharmony_ci return 1; 108e41f4b71Sopenharmony_ci } 109e41f4b71Sopenharmony_ci private isRenderStack() : number { 110e41f4b71Sopenharmony_ci console.log("Stack is rendered"); 111e41f4b71Sopenharmony_ci return 1; 112e41f4b71Sopenharmony_ci } 113e41f4b71Sopenharmony_ci private isRenderImage() : number { 114e41f4b71Sopenharmony_ci console.log("Image is rendered"); 115e41f4b71Sopenharmony_ci return 1; 116e41f4b71Sopenharmony_ci } 117e41f4b71Sopenharmony_ci private isRenderText() : number { 118e41f4b71Sopenharmony_ci console.log("Text is rendered"); 119e41f4b71Sopenharmony_ci return 1; 120e41f4b71Sopenharmony_ci } 121e41f4b71Sopenharmony_ci build() { 122e41f4b71Sopenharmony_ci Column() { 123e41f4b71Sopenharmony_ci // When you compile this code in API version 9, the IDE may tell you that 124e41f4b71Sopenharmony_ci // "Assigning the '@ObjectLink' decorated attribute 'uiStyle' to the '@ObjectLink' decorated attribute 'uiStyle' is not allowed. <etsLint>" 125e41f4b71Sopenharmony_ci // Yet, you can still run the code by Previewer. 126e41f4b71Sopenharmony_ci SpecialImage({ 127e41f4b71Sopenharmony_ci uiStyle: this.uiStyle 128e41f4b71Sopenharmony_ci }) 129e41f4b71Sopenharmony_ci Stack() { 130e41f4b71Sopenharmony_ci Column() { 131e41f4b71Sopenharmony_ci Image($r('app.media.icon')) 132e41f4b71Sopenharmony_ci .opacity(this.uiStyle.alpha) 133e41f4b71Sopenharmony_ci .scale({ 134e41f4b71Sopenharmony_ci x: this.uiStyle.scaleX, 135e41f4b71Sopenharmony_ci y: this.uiStyle.scaleY 136e41f4b71Sopenharmony_ci }) 137e41f4b71Sopenharmony_ci .padding(this.isRenderImage()) 138e41f4b71Sopenharmony_ci .width(300) 139e41f4b71Sopenharmony_ci .height(300) 140e41f4b71Sopenharmony_ci } 141e41f4b71Sopenharmony_ci .width('100%') 142e41f4b71Sopenharmony_ci .position({ y: -80 }) 143e41f4b71Sopenharmony_ci Stack() { 144e41f4b71Sopenharmony_ci Text("Hello World") 145e41f4b71Sopenharmony_ci .fontColor("#182431") 146e41f4b71Sopenharmony_ci .fontWeight(FontWeight.Medium) 147e41f4b71Sopenharmony_ci .fontSize(this.uiStyle.fontSize) 148e41f4b71Sopenharmony_ci .opacity(this.isRenderText()) 149e41f4b71Sopenharmony_ci .margin({ top: 12 }) 150e41f4b71Sopenharmony_ci } 151e41f4b71Sopenharmony_ci .opacity(this.isRenderStack()) 152e41f4b71Sopenharmony_ci .position({ 153e41f4b71Sopenharmony_ci x: this.uiStyle.posX, 154e41f4b71Sopenharmony_ci y: this.uiStyle.posY 155e41f4b71Sopenharmony_ci }) 156e41f4b71Sopenharmony_ci .width('100%') 157e41f4b71Sopenharmony_ci .height('100%') 158e41f4b71Sopenharmony_ci } 159e41f4b71Sopenharmony_ci .margin({ top: 50 }) 160e41f4b71Sopenharmony_ci .borderRadius(this.uiStyle.borderRadius) 161e41f4b71Sopenharmony_ci .opacity(this.isRenderStack()) 162e41f4b71Sopenharmony_ci .backgroundColor("#FFFFFF") 163e41f4b71Sopenharmony_ci .width(this.uiStyle.width) 164e41f4b71Sopenharmony_ci .height(this.uiStyle.height) 165e41f4b71Sopenharmony_ci .translate({ 166e41f4b71Sopenharmony_ci x: this.uiStyle.translateX, 167e41f4b71Sopenharmony_ci y: this.uiStyle.translateY 168e41f4b71Sopenharmony_ci }) 169e41f4b71Sopenharmony_ci Column() { 170e41f4b71Sopenharmony_ci Button("Move") 171e41f4b71Sopenharmony_ci .width(312) 172e41f4b71Sopenharmony_ci .fontSize(20) 173e41f4b71Sopenharmony_ci .backgroundColor("#FF007DFF") 174e41f4b71Sopenharmony_ci .margin({ bottom: 10 }) 175e41f4b71Sopenharmony_ci .onClick(() => { 176e41f4b71Sopenharmony_ci animateTo({ 177e41f4b71Sopenharmony_ci duration: 500 178e41f4b71Sopenharmony_ci },() => { 179e41f4b71Sopenharmony_ci this.uiStyle.translateY = (this.uiStyle.translateY + 180) % 250; 180e41f4b71Sopenharmony_ci }) 181e41f4b71Sopenharmony_ci }) 182e41f4b71Sopenharmony_ci Button("Scale") 183e41f4b71Sopenharmony_ci .borderRadius(20) 184e41f4b71Sopenharmony_ci .backgroundColor("#FF007DFF") 185e41f4b71Sopenharmony_ci .fontSize(20) 186e41f4b71Sopenharmony_ci .width(312) 187e41f4b71Sopenharmony_ci .onClick(() => { 188e41f4b71Sopenharmony_ci this.uiStyle.scaleX = (this.uiStyle.scaleX + 0.6) % 0.8; 189e41f4b71Sopenharmony_ci }) 190e41f4b71Sopenharmony_ci } 191e41f4b71Sopenharmony_ci .position({ 192e41f4b71Sopenharmony_ci y:666 193e41f4b71Sopenharmony_ci }) 194e41f4b71Sopenharmony_ci .height('100%') 195e41f4b71Sopenharmony_ci .width('100%') 196e41f4b71Sopenharmony_ci 197e41f4b71Sopenharmony_ci } 198e41f4b71Sopenharmony_ci .opacity(this.isRenderColumn()) 199e41f4b71Sopenharmony_ci .width('100%') 200e41f4b71Sopenharmony_ci .height('100%') 201e41f4b71Sopenharmony_ci 202e41f4b71Sopenharmony_ci } 203e41f4b71Sopenharmony_ci} 204e41f4b71Sopenharmony_ci@Entry 205e41f4b71Sopenharmony_ci@Component 206e41f4b71Sopenharmony_cistruct Page { 207e41f4b71Sopenharmony_ci @State uiStyle: UIStyle = new UIStyle(); 208e41f4b71Sopenharmony_ci build() { 209e41f4b71Sopenharmony_ci Stack() { 210e41f4b71Sopenharmony_ci CompA({ 211e41f4b71Sopenharmony_ci uiStyle: this.uiStyle 212e41f4b71Sopenharmony_ci }) 213e41f4b71Sopenharmony_ci } 214e41f4b71Sopenharmony_ci .backgroundColor("#F1F3F5") 215e41f4b71Sopenharmony_ci } 216e41f4b71Sopenharmony_ci} 217e41f4b71Sopenharmony_ci``` 218e41f4b71Sopenharmony_ci 219e41f4b71Sopenharmony_ciIn the above example, **uiStyle** defines multiple properties, which are each associated with multiple components. When some of these properties are changed at the click of a button, all the components associated with **uiStyle** are re-rendered according to the mechanism described above, even though they actually do not need to be re-rendered (because the properties of these components are not changed). The re-renders of these components can be observed through a series of defined **isRender** functions. When **Move** is clicked to perform the translation animation, the values of **translateX** and **translateY** change multiple times. As a result, redundant re-renders occur at each frame, which greatly worsen the application performance. 220e41f4b71Sopenharmony_ci 221e41f4b71Sopenharmony_ciThe following figure shows the code running. 222e41f4b71Sopenharmony_ci 223e41f4b71Sopenharmony_ci 224e41f4b71Sopenharmony_ci 225e41f4b71Sopenharmony_ciTo precisely control the component render scope and avoid redundant re-renders, it is recommended that you divide a large property object into several small property objects. 226e41f4b71Sopenharmony_ci 227e41f4b71Sopenharmony_ciTo achieve this purpose, it is first necessary to understand the mechanism for property change observation. 228e41f4b71Sopenharmony_ci 229e41f4b71Sopenharmony_ciBelow is sample code: 230e41f4b71Sopenharmony_ci 231e41f4b71Sopenharmony_ci```TS 232e41f4b71Sopenharmony_ci@Observed 233e41f4b71Sopenharmony_ciclass ClassB { 234e41f4b71Sopenharmony_ci subProp1: number = 100; 235e41f4b71Sopenharmony_ci} 236e41f4b71Sopenharmony_ci@Observed 237e41f4b71Sopenharmony_ciclass ClassA { 238e41f4b71Sopenharmony_ci prop1: number = 0; 239e41f4b71Sopenharmony_ci prop2: string = "This is Prop2"; 240e41f4b71Sopenharmony_ci prop3: ClassB = new ClassB(); 241e41f4b71Sopenharmony_ci} 242e41f4b71Sopenharmony_ci@Component 243e41f4b71Sopenharmony_cistruct CompA { 244e41f4b71Sopenharmony_ci @ObjectLink a: ClassA; 245e41f4b71Sopenharmony_ci private sizeFont: number = 30; // the private variable does not invoke rendering 246e41f4b71Sopenharmony_ci private isRenderText() : number { 247e41f4b71Sopenharmony_ci this.sizeFont++; // the change of sizeFont will not invoke rendering, but showing that the function is called 248e41f4b71Sopenharmony_ci console.log("Text prop2 is rendered"); 249e41f4b71Sopenharmony_ci return this.sizeFont; 250e41f4b71Sopenharmony_ci } 251e41f4b71Sopenharmony_ci build() { 252e41f4b71Sopenharmony_ci Column() { 253e41f4b71Sopenharmony_ci Text(this.a.prop2) // When this.a.prop1 changes, it will invoke <Text> re-rendering. 254e41f4b71Sopenharmony_ci .margin({ bottom: 10 }) 255e41f4b71Sopenharmony_ci .fontSize(this.isRenderText()) // If the <Text> renders, the function isRenderText will be called. 256e41f4b71Sopenharmony_ci Text("subProp1 : " + this.a.prop3.subProp1) //the Text can not observe the change of subProp1 257e41f4b71Sopenharmony_ci .fontSize(30) 258e41f4b71Sopenharmony_ci } 259e41f4b71Sopenharmony_ci } 260e41f4b71Sopenharmony_ci} 261e41f4b71Sopenharmony_ci@Entry 262e41f4b71Sopenharmony_ci@Component 263e41f4b71Sopenharmony_cistruct Page { 264e41f4b71Sopenharmony_ci @State a: ClassA = new ClassA(); 265e41f4b71Sopenharmony_ci build() { 266e41f4b71Sopenharmony_ci Row() { 267e41f4b71Sopenharmony_ci Column() { 268e41f4b71Sopenharmony_ci Text("Prop1: " + this.a.prop1) 269e41f4b71Sopenharmony_ci .margin({ bottom: 20 }) 270e41f4b71Sopenharmony_ci .fontSize(50) 271e41f4b71Sopenharmony_ci CompA({a: this.a}) 272e41f4b71Sopenharmony_ci Button("Change prop1") 273e41f4b71Sopenharmony_ci .width(200) 274e41f4b71Sopenharmony_ci .fontSize(20) 275e41f4b71Sopenharmony_ci .backgroundColor("#FF007DFF") 276e41f4b71Sopenharmony_ci .margin({ 277e41f4b71Sopenharmony_ci top: 10, 278e41f4b71Sopenharmony_ci bottom: 10 279e41f4b71Sopenharmony_ci }) 280e41f4b71Sopenharmony_ci .onClick(() => { 281e41f4b71Sopenharmony_ci this.a.prop1 = this.a.prop1 + 1 ; 282e41f4b71Sopenharmony_ci }) 283e41f4b71Sopenharmony_ci Button("Change subProp1") 284e41f4b71Sopenharmony_ci .width(200) 285e41f4b71Sopenharmony_ci .fontSize(20) 286e41f4b71Sopenharmony_ci .backgroundColor("#FF007DFF") 287e41f4b71Sopenharmony_ci .onClick(() => { 288e41f4b71Sopenharmony_ci this.a.prop3.subProp1 = this.a.prop3.subProp1 + 1; 289e41f4b71Sopenharmony_ci }) 290e41f4b71Sopenharmony_ci } 291e41f4b71Sopenharmony_ci .width('100%') 292e41f4b71Sopenharmony_ci } 293e41f4b71Sopenharmony_ci .width('100%') 294e41f4b71Sopenharmony_ci .height('100%') 295e41f4b71Sopenharmony_ci } 296e41f4b71Sopenharmony_ci} 297e41f4b71Sopenharmony_ci``` 298e41f4b71Sopenharmony_ci 299e41f4b71Sopenharmony_ciIn the preceding example, when **Change subProp1** is clicked, you can find that the page is not re-rendered. This is because the change to **subProp1** is not observed by the component. When **Change prop1** is clicked, the page is re-rendered, with the latest values of **prop1** and **subProp1** displayed. According to the ArkUI state management mechanism, the state variable can only observe the change at the first layer. For **Change subProp1**, the property value changes at the second layer and therefore cannot be observed. In other words, the change of **this.a.prop3.subProp1** does not cause component re-renders, even if the value of **subProp1** has changed. In comparison, the change of **this.a.prop1** causes component re-renders. 300e41f4b71Sopenharmony_ci 301e41f4b71Sopenharmony_ciThe following figure shows the code running. 302e41f4b71Sopenharmony_ci 303e41f4b71Sopenharmony_ci 304e41f4b71Sopenharmony_ci 305e41f4b71Sopenharmony_ciWith this mechanism of property change observation, the render scope of components can be precisely controlled. 306e41f4b71Sopenharmony_ci 307e41f4b71Sopenharmony_ci```ts 308e41f4b71Sopenharmony_ci@Observed 309e41f4b71Sopenharmony_ciclass ClassB { 310e41f4b71Sopenharmony_ci subProp1: number = 100; 311e41f4b71Sopenharmony_ci} 312e41f4b71Sopenharmony_ci@Observed 313e41f4b71Sopenharmony_ciclass ClassA { 314e41f4b71Sopenharmony_ci prop1: number = 0; 315e41f4b71Sopenharmony_ci prop2: string = "This is Prop2"; 316e41f4b71Sopenharmony_ci prop3: ClassB = new ClassB(); 317e41f4b71Sopenharmony_ci} 318e41f4b71Sopenharmony_ci@Component 319e41f4b71Sopenharmony_cistruct CompA { 320e41f4b71Sopenharmony_ci @ObjectLink a: ClassA; 321e41f4b71Sopenharmony_ci @ObjectLink b: ClassB; // A new @ObjectLink decorated variable. 322e41f4b71Sopenharmony_ci private sizeFont: number = 30; 323e41f4b71Sopenharmony_ci private isRenderText() : number { 324e41f4b71Sopenharmony_ci this.sizeFont++; 325e41f4b71Sopenharmony_ci console.log("Text prop2 is rendered"); 326e41f4b71Sopenharmony_ci return this.sizeFont; 327e41f4b71Sopenharmony_ci } 328e41f4b71Sopenharmony_ci private isRenderTextSubProp1() : number { 329e41f4b71Sopenharmony_ci this.sizeFont++; 330e41f4b71Sopenharmony_ci console.log("Text subProp1 is rendered"); 331e41f4b71Sopenharmony_ci return this.sizeFont; 332e41f4b71Sopenharmony_ci } 333e41f4b71Sopenharmony_ci build() { 334e41f4b71Sopenharmony_ci Column() { 335e41f4b71Sopenharmony_ci Text(this.a.prop2) // When this.a.prop1 changes, it will invoke <Text> re-rendering. 336e41f4b71Sopenharmony_ci .margin({ bottom: 10 }) 337e41f4b71Sopenharmony_ci .fontSize(this.isRenderText()) // If the <Text> renders, the function isRenderText will be called. 338e41f4b71Sopenharmony_ci Text("subProp1 : " + this.b.subProp1) // Use directly b rather than a.prop3. 339e41f4b71Sopenharmony_ci .fontSize(30) 340e41f4b71Sopenharmony_ci .opacity(this.isRenderTextSubProp1()) 341e41f4b71Sopenharmony_ci } 342e41f4b71Sopenharmony_ci } 343e41f4b71Sopenharmony_ci} 344e41f4b71Sopenharmony_ci@Entry 345e41f4b71Sopenharmony_ci@Component 346e41f4b71Sopenharmony_cistruct Page { 347e41f4b71Sopenharmony_ci @State a: ClassA = new ClassA(); 348e41f4b71Sopenharmony_ci build() { 349e41f4b71Sopenharmony_ci Row() { 350e41f4b71Sopenharmony_ci Column() { 351e41f4b71Sopenharmony_ci Text("Prop1: " + this.a.prop1) 352e41f4b71Sopenharmony_ci .margin({ bottom: 20 }) 353e41f4b71Sopenharmony_ci .fontSize(50) 354e41f4b71Sopenharmony_ci CompA({ 355e41f4b71Sopenharmony_ci a: this.a, 356e41f4b71Sopenharmony_ci b: this.a.prop3 357e41f4b71Sopenharmony_ci }) 358e41f4b71Sopenharmony_ci Button("Change prop1") 359e41f4b71Sopenharmony_ci .width(200) 360e41f4b71Sopenharmony_ci .fontSize(20) 361e41f4b71Sopenharmony_ci .backgroundColor("#FF007DFF") 362e41f4b71Sopenharmony_ci .margin({ 363e41f4b71Sopenharmony_ci top: 10, 364e41f4b71Sopenharmony_ci bottom: 10 365e41f4b71Sopenharmony_ci }) 366e41f4b71Sopenharmony_ci .onClick(() => { 367e41f4b71Sopenharmony_ci this.a.prop1 = this.a.prop1 + 1 ; 368e41f4b71Sopenharmony_ci }) 369e41f4b71Sopenharmony_ci Button("Change subProp1") 370e41f4b71Sopenharmony_ci .width(200) 371e41f4b71Sopenharmony_ci .fontSize(20) 372e41f4b71Sopenharmony_ci .backgroundColor("#FF007DFF") 373e41f4b71Sopenharmony_ci .margin({ 374e41f4b71Sopenharmony_ci top: 10, 375e41f4b71Sopenharmony_ci bottom: 10 376e41f4b71Sopenharmony_ci }) 377e41f4b71Sopenharmony_ci .onClick(() => { 378e41f4b71Sopenharmony_ci this.a.prop3.subProp1 = this.a.prop3.subProp1 + 1; 379e41f4b71Sopenharmony_ci }) 380e41f4b71Sopenharmony_ci } 381e41f4b71Sopenharmony_ci .width('100%') 382e41f4b71Sopenharmony_ci } 383e41f4b71Sopenharmony_ci .width('100%') 384e41f4b71Sopenharmony_ci .height('100%') 385e41f4b71Sopenharmony_ci } 386e41f4b71Sopenharmony_ci} 387e41f4b71Sopenharmony_ci``` 388e41f4b71Sopenharmony_ci 389e41f4b71Sopenharmony_ciIn the preceding example, a new variable **b** decorated by @ObjectLink is defined in **CompA**. When **CompA** is created on the page, **prop3** in object **a** is passed to **b**. In this way, **b** can be directly used in **CompA**. This means that, in effect, **CompA** is associated with **b** and can observe the change of **subProp1** in **b**. When **Change subProp1** is clicked, the associated **\<Text>** component is re-rendered, but other components are not (because these components are associated with **a**). Similarly, changes to other properties in **a** do not cause the **\<Text>** component to be re-rendered. 390e41f4b71Sopenharmony_ci 391e41f4b71Sopenharmony_ciThe following figure shows the code running. 392e41f4b71Sopenharmony_ci 393e41f4b71Sopenharmony_ci 394e41f4b71Sopenharmony_ci 395e41f4b71Sopenharmony_ciBy using the aforementioned method, properties in the foregoing complex redundant re-render scenario can be divided to optimize performance. 396e41f4b71Sopenharmony_ci 397e41f4b71Sopenharmony_ci```ts 398e41f4b71Sopenharmony_ci@Observed 399e41f4b71Sopenharmony_ciclass NeedRenderImage { // Properties only used in the same component can be divided into the same new divided class. 400e41f4b71Sopenharmony_ci public translateImageX: number = 0; 401e41f4b71Sopenharmony_ci public translateImageY: number = 0; 402e41f4b71Sopenharmony_ci public imageWidth:number = 78; 403e41f4b71Sopenharmony_ci public imageHeight:number = 78; 404e41f4b71Sopenharmony_ci} 405e41f4b71Sopenharmony_ci@Observed 406e41f4b71Sopenharmony_ciclass NeedRenderScale { // Properties usually used together can be divided into the same new child class. 407e41f4b71Sopenharmony_ci public scaleX: number = 0.3; 408e41f4b71Sopenharmony_ci public scaleY: number = 0.3; 409e41f4b71Sopenharmony_ci} 410e41f4b71Sopenharmony_ci@Observed 411e41f4b71Sopenharmony_ciclass NeedRenderAlpha { // Properties that may be used in different places can be divided into the same new child class. 412e41f4b71Sopenharmony_ci public alpha: number = 0.5; 413e41f4b71Sopenharmony_ci} 414e41f4b71Sopenharmony_ci@Observed 415e41f4b71Sopenharmony_ciclass NeedRenderSize { // Properties usually used together can be divided into the same new child class. 416e41f4b71Sopenharmony_ci public width: number = 336; 417e41f4b71Sopenharmony_ci public height: number = 178; 418e41f4b71Sopenharmony_ci} 419e41f4b71Sopenharmony_ci@Observed 420e41f4b71Sopenharmony_ciclass NeedRenderPos { // Properties usually used together can be divided into the same new child class. 421e41f4b71Sopenharmony_ci public posX: number = 10; 422e41f4b71Sopenharmony_ci public posY: number = 50; 423e41f4b71Sopenharmony_ci} 424e41f4b71Sopenharmony_ci@Observed 425e41f4b71Sopenharmony_ciclass NeedRenderBorderRadius { // Properties that may be used in different places can be divided into the same new child class. 426e41f4b71Sopenharmony_ci public borderRadius: number = 24; 427e41f4b71Sopenharmony_ci} 428e41f4b71Sopenharmony_ci@Observed 429e41f4b71Sopenharmony_ciclass NeedRenderFontSize { // Properties that may be used in different places can be divided into the same new child class. 430e41f4b71Sopenharmony_ci public fontSize: number = 20; 431e41f4b71Sopenharmony_ci} 432e41f4b71Sopenharmony_ci@Observed 433e41f4b71Sopenharmony_ciclass NeedRenderTranslate { // Properties usually used together can be divided into the same new child class. 434e41f4b71Sopenharmony_ci public translateX: number = 0; 435e41f4b71Sopenharmony_ci public translateY: number = 0; 436e41f4b71Sopenharmony_ci} 437e41f4b71Sopenharmony_ci@Observed 438e41f4b71Sopenharmony_ciclass UIStyle { 439e41f4b71Sopenharmony_ci // Define a new variable instead of using the old one. 440e41f4b71Sopenharmony_ci needRenderTranslate: NeedRenderTranslate = new NeedRenderTranslate(); 441e41f4b71Sopenharmony_ci needRenderFontSize: NeedRenderFontSize = new NeedRenderFontSize(); 442e41f4b71Sopenharmony_ci needRenderBorderRadius: NeedRenderBorderRadius = new NeedRenderBorderRadius(); 443e41f4b71Sopenharmony_ci needRenderPos: NeedRenderPos = new NeedRenderPos(); 444e41f4b71Sopenharmony_ci needRenderSize: NeedRenderSize = new NeedRenderSize(); 445e41f4b71Sopenharmony_ci needRenderAlpha: NeedRenderAlpha = new NeedRenderAlpha(); 446e41f4b71Sopenharmony_ci needRenderScale: NeedRenderScale = new NeedRenderScale(); 447e41f4b71Sopenharmony_ci needRenderImage: NeedRenderImage = new NeedRenderImage(); 448e41f4b71Sopenharmony_ci} 449e41f4b71Sopenharmony_ci@Component 450e41f4b71Sopenharmony_cistruct SpecialImage { 451e41f4b71Sopenharmony_ci @ObjectLink uiStyle : UIStyle; 452e41f4b71Sopenharmony_ci @ObjectLink needRenderImage: NeedRenderImage // Receive the new class from its parent component. 453e41f4b71Sopenharmony_ci private isRenderSpecialImage() : number { // Function to show whether the component is rendered. 454e41f4b71Sopenharmony_ci console.log("SpecialImage is rendered"); 455e41f4b71Sopenharmony_ci return 1; 456e41f4b71Sopenharmony_ci } 457e41f4b71Sopenharmony_ci build() { 458e41f4b71Sopenharmony_ci Image($r('app.media.icon')) 459e41f4b71Sopenharmony_ci .width(this.needRenderImage.imageWidth) // Attention: Use this.needRenderImage.xxx rather than this.uiStyle.needRenderImage.xxx. 460e41f4b71Sopenharmony_ci .height(this.needRenderImage.imageHeight) 461e41f4b71Sopenharmony_ci .margin({top:20}) 462e41f4b71Sopenharmony_ci .translate({ 463e41f4b71Sopenharmony_ci x: this.needRenderImage.translateImageX, 464e41f4b71Sopenharmony_ci y: this.needRenderImage.translateImageY 465e41f4b71Sopenharmony_ci }) 466e41f4b71Sopenharmony_ci .opacity(this.isRenderSpecialImage()) // If the <Image> is rendered, it will call the function. 467e41f4b71Sopenharmony_ci } 468e41f4b71Sopenharmony_ci} 469e41f4b71Sopenharmony_ci@Component 470e41f4b71Sopenharmony_cistruct CompA { 471e41f4b71Sopenharmony_ci @ObjectLink uiStyle: UIStyle; 472e41f4b71Sopenharmony_ci @ObjectLink needRenderTranslate: NeedRenderTranslate; // Receive the new class from its parent component. 473e41f4b71Sopenharmony_ci @ObjectLink needRenderFontSize: NeedRenderFontSize; 474e41f4b71Sopenharmony_ci @ObjectLink needRenderBorderRadius: NeedRenderBorderRadius; 475e41f4b71Sopenharmony_ci @ObjectLink needRenderPos: NeedRenderPos; 476e41f4b71Sopenharmony_ci @ObjectLink needRenderSize: NeedRenderSize; 477e41f4b71Sopenharmony_ci @ObjectLink needRenderAlpha: NeedRenderAlpha; 478e41f4b71Sopenharmony_ci @ObjectLink needRenderScale: NeedRenderScale; 479e41f4b71Sopenharmony_ci // The following functions are used to show whether the component is called to be rendered. 480e41f4b71Sopenharmony_ci private isRenderColumn() : number { 481e41f4b71Sopenharmony_ci console.log("Column is rendered"); 482e41f4b71Sopenharmony_ci return 1; 483e41f4b71Sopenharmony_ci } 484e41f4b71Sopenharmony_ci private isRenderStack() : number { 485e41f4b71Sopenharmony_ci console.log("Stack is rendered"); 486e41f4b71Sopenharmony_ci return 1; 487e41f4b71Sopenharmony_ci } 488e41f4b71Sopenharmony_ci private isRenderImage() : number { 489e41f4b71Sopenharmony_ci console.log("Image is rendered"); 490e41f4b71Sopenharmony_ci return 1; 491e41f4b71Sopenharmony_ci } 492e41f4b71Sopenharmony_ci private isRenderText() : number { 493e41f4b71Sopenharmony_ci console.log("Text is rendered"); 494e41f4b71Sopenharmony_ci return 1; 495e41f4b71Sopenharmony_ci } 496e41f4b71Sopenharmony_ci build() { 497e41f4b71Sopenharmony_ci Column() { 498e41f4b71Sopenharmony_ci // When you compile this code in API version 9, the IDE may tell you that 499e41f4b71Sopenharmony_ci // "Assigning the '@ObjectLink' decorated attribute 'uiStyle' to the '@ObjectLink' decorated attribute 'uiStyle' is not allowed. <etsLint>" 500e41f4b71Sopenharmony_ci // "Assigning the '@ObjectLink' decorated attribute 'uiStyle' to the '@ObjectLink' decorated attribute 'needRenderImage' is not allowed. <etsLint>" 501e41f4b71Sopenharmony_ci // Yet, you can still run the code by Previewer. 502e41f4b71Sopenharmony_ci SpecialImage({ 503e41f4b71Sopenharmony_ci uiStyle: this.uiStyle, 504e41f4b71Sopenharmony_ci needRenderImage: this.uiStyle.needRenderImage // Send it to its child. 505e41f4b71Sopenharmony_ci }) 506e41f4b71Sopenharmony_ci Stack() { 507e41f4b71Sopenharmony_ci Column() { 508e41f4b71Sopenharmony_ci Image($r('app.media.icon')) 509e41f4b71Sopenharmony_ci .opacity(this.needRenderAlpha.alpha) 510e41f4b71Sopenharmony_ci .scale({ 511e41f4b71Sopenharmony_ci x: this.needRenderScale.scaleX, // Use this.needRenderXxx.xxx rather than this.uiStyle.needRenderXxx.xxx. 512e41f4b71Sopenharmony_ci y: this.needRenderScale.scaleY 513e41f4b71Sopenharmony_ci }) 514e41f4b71Sopenharmony_ci .padding(this.isRenderImage()) 515e41f4b71Sopenharmony_ci .width(300) 516e41f4b71Sopenharmony_ci .height(300) 517e41f4b71Sopenharmony_ci } 518e41f4b71Sopenharmony_ci .width('100%') 519e41f4b71Sopenharmony_ci .position({ y: -80 }) 520e41f4b71Sopenharmony_ci 521e41f4b71Sopenharmony_ci Stack() { 522e41f4b71Sopenharmony_ci Text("Hello World") 523e41f4b71Sopenharmony_ci .fontColor("#182431") 524e41f4b71Sopenharmony_ci .fontWeight(FontWeight.Medium) 525e41f4b71Sopenharmony_ci .fontSize(this.needRenderFontSize.fontSize) 526e41f4b71Sopenharmony_ci .opacity(this.isRenderText()) 527e41f4b71Sopenharmony_ci .margin({ top: 12 }) 528e41f4b71Sopenharmony_ci } 529e41f4b71Sopenharmony_ci .opacity(this.isRenderStack()) 530e41f4b71Sopenharmony_ci .position({ 531e41f4b71Sopenharmony_ci x: this.needRenderPos.posX, 532e41f4b71Sopenharmony_ci y: this.needRenderPos.posY 533e41f4b71Sopenharmony_ci }) 534e41f4b71Sopenharmony_ci .width('100%') 535e41f4b71Sopenharmony_ci .height('100%') 536e41f4b71Sopenharmony_ci } 537e41f4b71Sopenharmony_ci .margin({ top: 50 }) 538e41f4b71Sopenharmony_ci .borderRadius(this.needRenderBorderRadius.borderRadius) 539e41f4b71Sopenharmony_ci .opacity(this.isRenderStack()) 540e41f4b71Sopenharmony_ci .backgroundColor("#FFFFFF") 541e41f4b71Sopenharmony_ci .width(this.needRenderSize.width) 542e41f4b71Sopenharmony_ci .height(this.needRenderSize.height) 543e41f4b71Sopenharmony_ci .translate({ 544e41f4b71Sopenharmony_ci x: this.needRenderTranslate.translateX, 545e41f4b71Sopenharmony_ci y: this.needRenderTranslate.translateY 546e41f4b71Sopenharmony_ci }) 547e41f4b71Sopenharmony_ci 548e41f4b71Sopenharmony_ci Column() { 549e41f4b71Sopenharmony_ci Button("Move") 550e41f4b71Sopenharmony_ci .width(312) 551e41f4b71Sopenharmony_ci .fontSize(20) 552e41f4b71Sopenharmony_ci .backgroundColor("#FF007DFF") 553e41f4b71Sopenharmony_ci .margin({ bottom: 10 }) 554e41f4b71Sopenharmony_ci .onClick(() => { 555e41f4b71Sopenharmony_ci animateTo({ 556e41f4b71Sopenharmony_ci duration: 500 557e41f4b71Sopenharmony_ci }, () => { 558e41f4b71Sopenharmony_ci this.needRenderTranslate.translateY = (this.needRenderTranslate.translateY + 180) % 250; 559e41f4b71Sopenharmony_ci }) 560e41f4b71Sopenharmony_ci }) 561e41f4b71Sopenharmony_ci Button("Scale") 562e41f4b71Sopenharmony_ci .borderRadius(20) 563e41f4b71Sopenharmony_ci .backgroundColor("#FF007DFF") 564e41f4b71Sopenharmony_ci .fontSize(20) 565e41f4b71Sopenharmony_ci .width(312) 566e41f4b71Sopenharmony_ci .margin({ bottom: 10 }) 567e41f4b71Sopenharmony_ci .onClick(() => { 568e41f4b71Sopenharmony_ci this.needRenderScale.scaleX = (this.needRenderScale.scaleX + 0.6) % 0.8; 569e41f4b71Sopenharmony_ci }) 570e41f4b71Sopenharmony_ci Button("Change Image") 571e41f4b71Sopenharmony_ci .borderRadius(20) 572e41f4b71Sopenharmony_ci .backgroundColor("#FF007DFF") 573e41f4b71Sopenharmony_ci .fontSize(20) 574e41f4b71Sopenharmony_ci .width(312) 575e41f4b71Sopenharmony_ci .onClick(() => { // In the parent component, still use this.uiStyle.needRenderXxx.xxx to change the properties. 576e41f4b71Sopenharmony_ci this.uiStyle.needRenderImage.imageWidth = (this.uiStyle.needRenderImage.imageWidth + 30) % 160; 577e41f4b71Sopenharmony_ci this.uiStyle.needRenderImage.imageHeight = (this.uiStyle.needRenderImage.imageHeight + 30) % 160; 578e41f4b71Sopenharmony_ci }) 579e41f4b71Sopenharmony_ci } 580e41f4b71Sopenharmony_ci .position({ 581e41f4b71Sopenharmony_ci y: 616 582e41f4b71Sopenharmony_ci }) 583e41f4b71Sopenharmony_ci .height('100%') 584e41f4b71Sopenharmony_ci .width('100%') 585e41f4b71Sopenharmony_ci } 586e41f4b71Sopenharmony_ci .opacity(this.isRenderColumn()) 587e41f4b71Sopenharmony_ci .width('100%') 588e41f4b71Sopenharmony_ci .height('100%') 589e41f4b71Sopenharmony_ci } 590e41f4b71Sopenharmony_ci} 591e41f4b71Sopenharmony_ci@Entry 592e41f4b71Sopenharmony_ci@Component 593e41f4b71Sopenharmony_cistruct Page { 594e41f4b71Sopenharmony_ci @State uiStyle: UIStyle = new UIStyle(); 595e41f4b71Sopenharmony_ci build() { 596e41f4b71Sopenharmony_ci Stack() { 597e41f4b71Sopenharmony_ci CompA({ 598e41f4b71Sopenharmony_ci uiStyle: this.uiStyle, 599e41f4b71Sopenharmony_ci needRenderTranslate: this.uiStyle.needRenderTranslate, // Send all the new class child need. 600e41f4b71Sopenharmony_ci needRenderFontSize: this.uiStyle.needRenderFontSize, 601e41f4b71Sopenharmony_ci needRenderBorderRadius: this.uiStyle.needRenderBorderRadius, 602e41f4b71Sopenharmony_ci needRenderPos: this.uiStyle.needRenderPos, 603e41f4b71Sopenharmony_ci needRenderSize: this.uiStyle.needRenderSize, 604e41f4b71Sopenharmony_ci needRenderAlpha: this.uiStyle.needRenderAlpha, 605e41f4b71Sopenharmony_ci needRenderScale: this.uiStyle.needRenderScale 606e41f4b71Sopenharmony_ci }) 607e41f4b71Sopenharmony_ci } 608e41f4b71Sopenharmony_ci .backgroundColor("#F1F3F5") 609e41f4b71Sopenharmony_ci } 610e41f4b71Sopenharmony_ci} 611e41f4b71Sopenharmony_ci``` 612e41f4b71Sopenharmony_ci 613e41f4b71Sopenharmony_ciThe following figure shows the code running. 614e41f4b71Sopenharmony_ci 615e41f4b71Sopenharmony_ci 616e41f4b71Sopenharmony_ci 617e41f4b71Sopenharmony_ciIn the preceding example, the 15 properties in the original class are divided into eight child classes, and the corresponding adaptation is performed on the binding between properties and components. Division of properties complies with the following principles: 618e41f4b71Sopenharmony_ci 619e41f4b71Sopenharmony_ci- Properties that are only used in the same component can be divided into the same new child class, that is, **NeedRenderImage** in the example. This mode of division is applicable to the scenario where components are frequently re-rendered due to changes of unassociated properties. In this scenario, divide the properties or review the view model design. 620e41f4b71Sopenharmony_ci- Properties that are frequently used together can be divided into the same new child class, that is, **NeedRenderScale**, **NeedRenderTranslate**, **NeedRenderPos**, and **NeedRenderSize** in the example. This mode of division is applicable to the scenario where properties often appear in pairs or are applied to the same style, for example, **.translate**, **.position**, and **.scale** (which usually receive an object as a parameter). 621e41f4b71Sopenharmony_ci- Properties that may be used in different places should be divided into a new child class, that is, **NeedRenderAlpha**, **NeedRenderBorderRadius**, and **NeedRenderFontSize** in the example. This mode of division is applicable to the scenario where a property works on multiple components or is not related to other properties, for example, **.opacity** and **.borderRadius** (which usually work on their own). 622e41f4b71Sopenharmony_ci 623e41f4b71Sopenharmony_ciAfter properties are divided, use the following format to bind components using the properties: 624e41f4b71Sopenharmony_ci 625e41f4b71Sopenharmony_ci```ts 626e41f4b71Sopenharmony_ci.property(this.needRenderXxx.xxx) 627e41f4b71Sopenharmony_ci 628e41f4b71Sopenharmony_ci// sample 629e41f4b71Sopenharmony_ciText("some text") 630e41f4b71Sopenharmony_ci.width(this.needRenderSize.width) 631e41f4b71Sopenharmony_ci.height(this.needRenderSize.height) 632e41f4b71Sopenharmony_ci.opacity(this.needRenderAlpha.alpha) 633e41f4b71Sopenharmony_ci``` 634e41f4b71Sopenharmony_ci 635e41f4b71Sopenharmony_ciIf changes of a property apply to the parent component, the property can be changed through the outer parent class. 636e41f4b71Sopenharmony_ci 637e41f4b71Sopenharmony_ci```ts 638e41f4b71Sopenharmony_ci// In parent Component 639e41f4b71Sopenharmony_cithis.parent.needRenderXxx.xxx = x; 640e41f4b71Sopenharmony_ci 641e41f4b71Sopenharmony_ci// Example 642e41f4b71Sopenharmony_cithis.uiStyle.needRenderImage.imageWidth = (this.uiStyle.needRenderImage.imageWidth + 20) % 60; 643e41f4b71Sopenharmony_ci``` 644e41f4b71Sopenharmony_ci 645e41f4b71Sopenharmony_ciIf changes of a property apply to the child component, it is recommended that the property be changed through the new child class. 646e41f4b71Sopenharmony_ci 647e41f4b71Sopenharmony_ci```ts 648e41f4b71Sopenharmony_ci// In child Component 649e41f4b71Sopenharmony_cithis.needRenderXxx.xxx = x; 650e41f4b71Sopenharmony_ci 651e41f4b71Sopenharmony_ci// Example 652e41f4b71Sopenharmony_cithis.needRenderScale.scaleX = (this.needRenderScale.scaleX + 0.6) % 1 653e41f4b71Sopenharmony_ci``` 654e41f4b71Sopenharmony_ci 655e41f4b71Sopenharmony_ciWhen dividing properties to speed up applications, focus on properties that change frequently. 656e41f4b71Sopenharmony_ci 657e41f4b71Sopenharmony_ciIf you want to use the divided properties in the parent component, you are advised to define a new @State decorated state variable and use them together. 658e41f4b71Sopenharmony_ci 659e41f4b71Sopenharmony_ci```ts 660e41f4b71Sopenharmony_ci@Observed 661e41f4b71Sopenharmony_ciclass NeedRenderProperty { 662e41f4b71Sopenharmony_ci public property: number = 1; 663e41f4b71Sopenharmony_ci}; 664e41f4b71Sopenharmony_ci@Observed 665e41f4b71Sopenharmony_ciclass SomeClass { 666e41f4b71Sopenharmony_ci needRenderProperty: NeedRenderProperty = new NeedRenderProperty(); 667e41f4b71Sopenharmony_ci} 668e41f4b71Sopenharmony_ci@Entry 669e41f4b71Sopenharmony_ci@Component 670e41f4b71Sopenharmony_cistruct Page { 671e41f4b71Sopenharmony_ci @State someClass: SomeClass = new SomeClass(); 672e41f4b71Sopenharmony_ci @State needRenderProperty: NeedRenderProperty = this.someClass.needRenderProperty 673e41f4b71Sopenharmony_ci build() { 674e41f4b71Sopenharmony_ci Row() { 675e41f4b71Sopenharmony_ci Column() { 676e41f4b71Sopenharmony_ci Text("property value: " + this.needRenderProperty.property) 677e41f4b71Sopenharmony_ci .fontSize(30) 678e41f4b71Sopenharmony_ci .margin({ bottom: 20 }) 679e41f4b71Sopenharmony_ci Button("Change property") 680e41f4b71Sopenharmony_ci .onClick(() => { 681e41f4b71Sopenharmony_ci this.needRenderProperty.property++; 682e41f4b71Sopenharmony_ci }) 683e41f4b71Sopenharmony_ci } 684e41f4b71Sopenharmony_ci .width('100%') 685e41f4b71Sopenharmony_ci } 686e41f4b71Sopenharmony_ci .width('100%') 687e41f4b71Sopenharmony_ci .height('100%') 688e41f4b71Sopenharmony_ci } 689e41f4b71Sopenharmony_ci} 690e41f4b71Sopenharmony_ci``` 691