1e41f4b71Sopenharmony_ci# \@Param:组件外部输入 2e41f4b71Sopenharmony_ci 3e41f4b71Sopenharmony_ci 4e41f4b71Sopenharmony_ci为了增强子组件接受外部参数输入的能力,开发者可以使用\@Param装饰器。 5e41f4b71Sopenharmony_ci 6e41f4b71Sopenharmony_ci> **说明:** 7e41f4b71Sopenharmony_ci> 8e41f4b71Sopenharmony_ci> 从API version 12开始,在\@ComponentV2装饰的自定义组件中支持使用\@Param装饰器。 9e41f4b71Sopenharmony_ci> 10e41f4b71Sopenharmony_ci>当前状态管理(V2试用版)仍在逐步开发中,相关功能尚未成熟,建议开发者尝鲜试用。 11e41f4b71Sopenharmony_ci 12e41f4b71Sopenharmony_ci 13e41f4b71Sopenharmony_ci 14e41f4b71Sopenharmony_ci## 概述 15e41f4b71Sopenharmony_ci 16e41f4b71Sopenharmony_ci\@Param表示组件从外部传入的状态,使得父子组件之间的数据能够进行同步: 17e41f4b71Sopenharmony_ci 18e41f4b71Sopenharmony_ci- \@Param装饰的变量支持本地初始化,但是不允许在组件内部直接修改变量本身。 19e41f4b71Sopenharmony_ci 20e41f4b71Sopenharmony_ci- 被\@Param装饰的变量能够在初始化自定义组件时从外部传入,当数据源也是状态变量时,数据源的修改会同步给\@Param。 21e41f4b71Sopenharmony_ci- \@Param可以接受任意类型的数据源,包括普通变量、状态变量、常量、函数返回值等。 22e41f4b71Sopenharmony_ci- \@Param装饰的变量变化时,会刷新该变量关联的组件。 23e41f4b71Sopenharmony_ci- \@Param支持观测number、boolean、string、Object、class等基本类型以及Array、Set、Map、Date等内嵌类型。 24e41f4b71Sopenharmony_ci- 对于复杂类型如类对象,\@Param会接受数据源的引用。在组件内可以修改类对象中的属性,该修改会同步到数据源。 25e41f4b71Sopenharmony_ci- \@Param的观测能力仅限于被装饰的变量本身。当装饰简单类型时,对变量的整体改变能够观测到;当装饰对象类型时,仅能观测对象整体的改变;当装饰数组类型时,能观测到数组整体以及数组元素项的改变;当装饰Array、Set、Map、Date等内嵌类型时,可以观测到通过API调用带来的变化。详见[观察变化](#观察变化)。 26e41f4b71Sopenharmony_ci- \@Param支持null、undefined以及联合类型。 27e41f4b71Sopenharmony_ci 28e41f4b71Sopenharmony_ci 29e41f4b71Sopenharmony_ci## 状态管理V1版本接受外部传入的装饰器的局限性 30e41f4b71Sopenharmony_ci状态管理V1存在多种可接受外部传入的装饰器,常用的有\@State、\@Prop、\@Link、\@ObjectLink。这些装饰器使用各有限制,不易区分,当使用不当时,还会导致性能问题。 31e41f4b71Sopenharmony_ci 32e41f4b71Sopenharmony_ci```ts 33e41f4b71Sopenharmony_ci@Observed 34e41f4b71Sopenharmony_ciclass Region { 35e41f4b71Sopenharmony_ci x: number; 36e41f4b71Sopenharmony_ci y: number; 37e41f4b71Sopenharmony_ci constructor(x: number, y: number) { 38e41f4b71Sopenharmony_ci this.x = x; 39e41f4b71Sopenharmony_ci this.y = y; 40e41f4b71Sopenharmony_ci } 41e41f4b71Sopenharmony_ci} 42e41f4b71Sopenharmony_ci@Observed 43e41f4b71Sopenharmony_ciclass Info { 44e41f4b71Sopenharmony_ci region: Region; 45e41f4b71Sopenharmony_ci constructor(x: number, y: number) { 46e41f4b71Sopenharmony_ci this.region = new Region(x, y); 47e41f4b71Sopenharmony_ci } 48e41f4b71Sopenharmony_ci} 49e41f4b71Sopenharmony_ci@Entry 50e41f4b71Sopenharmony_ci@Component 51e41f4b71Sopenharmony_cistruct Index { 52e41f4b71Sopenharmony_ci @State info: Info = new Info(0, 0); 53e41f4b71Sopenharmony_ci 54e41f4b71Sopenharmony_ci build() { 55e41f4b71Sopenharmony_ci Column() { 56e41f4b71Sopenharmony_ci Button("change Info") 57e41f4b71Sopenharmony_ci .onClick(() => { 58e41f4b71Sopenharmony_ci this.info = new Info(100, 100); 59e41f4b71Sopenharmony_ci }) 60e41f4b71Sopenharmony_ci Child({ 61e41f4b71Sopenharmony_ci region: this.info.region, 62e41f4b71Sopenharmony_ci regionProp: this.info.region, 63e41f4b71Sopenharmony_ci infoProp: this.info, 64e41f4b71Sopenharmony_ci infoLink: this.info, 65e41f4b71Sopenharmony_ci infoState: this.info 66e41f4b71Sopenharmony_ci }) 67e41f4b71Sopenharmony_ci } 68e41f4b71Sopenharmony_ci } 69e41f4b71Sopenharmony_ci} 70e41f4b71Sopenharmony_ci@Component 71e41f4b71Sopenharmony_cistruct Child { 72e41f4b71Sopenharmony_ci @ObjectLink region: Region; 73e41f4b71Sopenharmony_ci @Prop regionProp: Region; 74e41f4b71Sopenharmony_ci @Prop infoProp: Info; 75e41f4b71Sopenharmony_ci @Link infoLink: Info; 76e41f4b71Sopenharmony_ci @State infoState: Info = new Info(1, 1); 77e41f4b71Sopenharmony_ci build() { 78e41f4b71Sopenharmony_ci Column() { 79e41f4b71Sopenharmony_ci Text(`ObjectLink region: ${this.region.x}-${this.region.y}`) 80e41f4b71Sopenharmony_ci Text(`Prop regionProp: ${this.regionProp.x}-${this.regionProp.y}`) 81e41f4b71Sopenharmony_ci } 82e41f4b71Sopenharmony_ci } 83e41f4b71Sopenharmony_ci} 84e41f4b71Sopenharmony_ci``` 85e41f4b71Sopenharmony_ci 86e41f4b71Sopenharmony_ci在上面的示例中,\@State仅能在初始化时获得info的引用,当改变info之后,无法进行同步。\@Prop虽然能够进行单向同步,但是对于较复杂的类型来说,深拷贝性能较差。\@Link能够接受传入的引用进行双向同步,但它必须要求数据源也是状态变量,因此无法接受info中的成员属性region。\@ObjectLink能够接受类成员属性,但是要求该属性类型必须为\@Observed装饰的类。装饰器的不同限制使得父子组件之间传值规则十分复杂,不易使用。因此推出\@Param装饰器表示组件从外部传入的状态。 87e41f4b71Sopenharmony_ci 88e41f4b71Sopenharmony_ci## 装饰器说明 89e41f4b71Sopenharmony_ci 90e41f4b71Sopenharmony_ci| \@Param变量装饰器 | 说明 | 91e41f4b71Sopenharmony_ci| ------------------ | ------------------------------------------------------------ | 92e41f4b71Sopenharmony_ci| 装饰器参数 | 无。 | 93e41f4b71Sopenharmony_ci| 能否本地修改 | 否,修改值需使用\@Event装饰器的能力。 | 94e41f4b71Sopenharmony_ci| 同步类型 | 由父到子单向同步。 | 95e41f4b71Sopenharmony_ci| 允许装饰的变量类型 | Object、class、string、number、boolean、enum等基本类型以及Array、Date、Map、Set等内嵌类型。支持null、undefined以及联合类型。 | 96e41f4b71Sopenharmony_ci| 被装饰变量的初始值 | 允许本地初始化,若不在本地初始化,则需要和\@Require装饰器一起使用,要求必须从外部传入初始化。 | 97e41f4b71Sopenharmony_ci 98e41f4b71Sopenharmony_ci## 变量传递 99e41f4b71Sopenharmony_ci 100e41f4b71Sopenharmony_ci| 传递规则 | 说明 | 101e41f4b71Sopenharmony_ci| -------------- | ------------------------------------------------------------ | 102e41f4b71Sopenharmony_ci| 从父组件初始化 | \@Param装饰的变量允许本地初始化,若无本地初始化则必须从外部传入初始化。当同时存在本地初始值与外部传入值时,会优先使用外部传入值进行初始化 | 103e41f4b71Sopenharmony_ci| 初始化子组件 | \@Param装饰的变量可以初始化子组件中\@Param装饰的变量。 | 104e41f4b71Sopenharmony_ci| 同步 | \@Param可以和父组件传入的状态变量数据源(即\@Local或\@Param装饰的变量)进行同步,当数据源发生变化时,会将修改同步给子组件的\@Param。 | 105e41f4b71Sopenharmony_ci 106e41f4b71Sopenharmony_ci## 观察变化 107e41f4b71Sopenharmony_ci 108e41f4b71Sopenharmony_ci使用\@Param装饰的变量具有被观测变化的能力。当装饰的变量发生变化时,会触发该变量绑定的UI组件刷新。 109e41f4b71Sopenharmony_ci 110e41f4b71Sopenharmony_ci- 当装饰的变量类型为boolean、string、number类型时,可以观察来自数据源同步的变化。 111e41f4b71Sopenharmony_ci 112e41f4b71Sopenharmony_ci ```ts 113e41f4b71Sopenharmony_ci @Entry 114e41f4b71Sopenharmony_ci @ComponentV2 115e41f4b71Sopenharmony_ci struct Index { 116e41f4b71Sopenharmony_ci @Local count: number = 0; 117e41f4b71Sopenharmony_ci @Local message: string = "Hello"; 118e41f4b71Sopenharmony_ci @Local flag: boolean = false; 119e41f4b71Sopenharmony_ci build() { 120e41f4b71Sopenharmony_ci Column() { 121e41f4b71Sopenharmony_ci Text(`Local ${this.count}`) 122e41f4b71Sopenharmony_ci Text(`Local ${this.message}`) 123e41f4b71Sopenharmony_ci Text(`Local ${this.flag}`) 124e41f4b71Sopenharmony_ci Button("change Local") 125e41f4b71Sopenharmony_ci .onClick(()=>{ 126e41f4b71Sopenharmony_ci // 对数据源的更改会同步给子组件 127e41f4b71Sopenharmony_ci this.count++; 128e41f4b71Sopenharmony_ci this.message += " World"; 129e41f4b71Sopenharmony_ci this.flag = !this.flag; 130e41f4b71Sopenharmony_ci }) 131e41f4b71Sopenharmony_ci Child({ 132e41f4b71Sopenharmony_ci count: this.count, 133e41f4b71Sopenharmony_ci message: this.message, 134e41f4b71Sopenharmony_ci flag: this.flag 135e41f4b71Sopenharmony_ci }) 136e41f4b71Sopenharmony_ci } 137e41f4b71Sopenharmony_ci } 138e41f4b71Sopenharmony_ci } 139e41f4b71Sopenharmony_ci @ComponentV2 140e41f4b71Sopenharmony_ci struct Child { 141e41f4b71Sopenharmony_ci @Require @Param count: number; 142e41f4b71Sopenharmony_ci @Require @Param message: string; 143e41f4b71Sopenharmony_ci @Require @Param flag: boolean; 144e41f4b71Sopenharmony_ci build() { 145e41f4b71Sopenharmony_ci Column() { 146e41f4b71Sopenharmony_ci Text(`Param ${this.count}`) 147e41f4b71Sopenharmony_ci Text(`Param ${this.message}`) 148e41f4b71Sopenharmony_ci Text(`Param ${this.flag}`) 149e41f4b71Sopenharmony_ci } 150e41f4b71Sopenharmony_ci } 151e41f4b71Sopenharmony_ci } 152e41f4b71Sopenharmony_ci ``` 153e41f4b71Sopenharmony_ci 154e41f4b71Sopenharmony_ci- 当装饰的变量类型为类对象时,仅可以观察到对类对象整体赋值的变化,无法直接观察到对类成员属性赋值的变化,对类成员属性的观察依赖\@ObservedV2和\@Trace装饰器。 155e41f4b71Sopenharmony_ci 156e41f4b71Sopenharmony_ci ```ts 157e41f4b71Sopenharmony_ci class RawObject { 158e41f4b71Sopenharmony_ci name: string; 159e41f4b71Sopenharmony_ci constructor(name: string) { 160e41f4b71Sopenharmony_ci this.name = name; 161e41f4b71Sopenharmony_ci } 162e41f4b71Sopenharmony_ci } 163e41f4b71Sopenharmony_ci @ObservedV2 164e41f4b71Sopenharmony_ci class ObservedObject { 165e41f4b71Sopenharmony_ci @Trace name: string; 166e41f4b71Sopenharmony_ci constructor(name: string) { 167e41f4b71Sopenharmony_ci this.name = name; 168e41f4b71Sopenharmony_ci } 169e41f4b71Sopenharmony_ci } 170e41f4b71Sopenharmony_ci @Entry 171e41f4b71Sopenharmony_ci @ComponentV2 172e41f4b71Sopenharmony_ci struct Index { 173e41f4b71Sopenharmony_ci @Local rawObject: RawObject = new RawObject("rawObject"); 174e41f4b71Sopenharmony_ci @Local observedObject: ObservedObject = new ObservedObject("observedObject"); 175e41f4b71Sopenharmony_ci build() { 176e41f4b71Sopenharmony_ci Column() { 177e41f4b71Sopenharmony_ci Text(`${this.rawObject.name}`) 178e41f4b71Sopenharmony_ci Text(`${this.observedObject.name}`) 179e41f4b71Sopenharmony_ci Button("change object") 180e41f4b71Sopenharmony_ci .onClick(() => { 181e41f4b71Sopenharmony_ci // 对类对象整体的修改均能观察到 182e41f4b71Sopenharmony_ci this.rawObject = new RawObject("new rawObject"); 183e41f4b71Sopenharmony_ci this.observedObject = new ObservedObject("new observedObject"); 184e41f4b71Sopenharmony_ci }) 185e41f4b71Sopenharmony_ci Button("change name") 186e41f4b71Sopenharmony_ci .onClick(() => { 187e41f4b71Sopenharmony_ci // \@Local与\@Param均不具备观察类对象属性的能力,因此对rawObject.name的修改无法观察到 188e41f4b71Sopenharmony_ci this.rawObject.name = "new rawObject name"; 189e41f4b71Sopenharmony_ci // 由于ObservedObject的name属性被@Trace装饰,因此对observedObject.name的修改能被观察到 190e41f4b71Sopenharmony_ci this.observedObject.name = "new observedObject name"; 191e41f4b71Sopenharmony_ci }) 192e41f4b71Sopenharmony_ci Child({ 193e41f4b71Sopenharmony_ci rawObject: this.rawObject, 194e41f4b71Sopenharmony_ci observedObject: this.observedObject 195e41f4b71Sopenharmony_ci }) 196e41f4b71Sopenharmony_ci } 197e41f4b71Sopenharmony_ci } 198e41f4b71Sopenharmony_ci } 199e41f4b71Sopenharmony_ci @ComponentV2 200e41f4b71Sopenharmony_ci struct Child { 201e41f4b71Sopenharmony_ci @Require @Param rawObject: RawObject; 202e41f4b71Sopenharmony_ci @Require @Param observedObject: ObservedObject; 203e41f4b71Sopenharmony_ci build() { 204e41f4b71Sopenharmony_ci Column() { 205e41f4b71Sopenharmony_ci Text(`${this.rawObject.name}`) 206e41f4b71Sopenharmony_ci Text(`${this.observedObject.name}`) 207e41f4b71Sopenharmony_ci } 208e41f4b71Sopenharmony_ci } 209e41f4b71Sopenharmony_ci 210e41f4b71Sopenharmony_ci } 211e41f4b71Sopenharmony_ci ``` 212e41f4b71Sopenharmony_ci 213e41f4b71Sopenharmony_ci- 当装饰的变量类型为简单类型的数组时,可以观察到数组整体或数组项的变化。 214e41f4b71Sopenharmony_ci 215e41f4b71Sopenharmony_ci ```ts 216e41f4b71Sopenharmony_ci @Entry 217e41f4b71Sopenharmony_ci @ComponentV2 218e41f4b71Sopenharmony_ci struct Index { 219e41f4b71Sopenharmony_ci @Local numArr: number[] = [1,2,3,4,5]; 220e41f4b71Sopenharmony_ci @Local dimensionTwo: number[][] = [[1,2,3],[4,5,6]]; 221e41f4b71Sopenharmony_ci 222e41f4b71Sopenharmony_ci build() { 223e41f4b71Sopenharmony_ci Column() { 224e41f4b71Sopenharmony_ci Text(`${this.numArr[0]}`) 225e41f4b71Sopenharmony_ci Text(`${this.numArr[1]}`) 226e41f4b71Sopenharmony_ci Text(`${this.numArr[2]}`) 227e41f4b71Sopenharmony_ci Text(`${this.dimensionTwo[0][0]}`) 228e41f4b71Sopenharmony_ci Text(`${this.dimensionTwo[1][1]}`) 229e41f4b71Sopenharmony_ci Button("change array item") 230e41f4b71Sopenharmony_ci .onClick(() => { 231e41f4b71Sopenharmony_ci this.numArr[0]++; 232e41f4b71Sopenharmony_ci this.numArr[1] += 2; 233e41f4b71Sopenharmony_ci this.dimensionTwo[0][0] = 0; 234e41f4b71Sopenharmony_ci this.dimensionTwo[1][1] = 0; 235e41f4b71Sopenharmony_ci }) 236e41f4b71Sopenharmony_ci Button("change whole array") 237e41f4b71Sopenharmony_ci .onClick(() => { 238e41f4b71Sopenharmony_ci this.numArr = [5,4,3,2,1]; 239e41f4b71Sopenharmony_ci this.dimensionTwo = [[7,8,9],[0,1,2]]; 240e41f4b71Sopenharmony_ci }) 241e41f4b71Sopenharmony_ci Child({ 242e41f4b71Sopenharmony_ci numArr: this.numArr, 243e41f4b71Sopenharmony_ci dimensionTwo: this.dimensionTwo 244e41f4b71Sopenharmony_ci }) 245e41f4b71Sopenharmony_ci } 246e41f4b71Sopenharmony_ci } 247e41f4b71Sopenharmony_ci } 248e41f4b71Sopenharmony_ci @ComponentV2 249e41f4b71Sopenharmony_ci struct Child { 250e41f4b71Sopenharmony_ci @Require @Param numArr: number[]; 251e41f4b71Sopenharmony_ci @Require @Param dimensionTwo: number[][]; 252e41f4b71Sopenharmony_ci 253e41f4b71Sopenharmony_ci build() { 254e41f4b71Sopenharmony_ci Column() { 255e41f4b71Sopenharmony_ci Text(`${this.numArr[0]}`) 256e41f4b71Sopenharmony_ci Text(`${this.numArr[1]}`) 257e41f4b71Sopenharmony_ci Text(`${this.numArr[2]}`) 258e41f4b71Sopenharmony_ci Text(`${this.dimensionTwo[0][0]}`) 259e41f4b71Sopenharmony_ci Text(`${this.dimensionTwo[1][1]}`) 260e41f4b71Sopenharmony_ci } 261e41f4b71Sopenharmony_ci } 262e41f4b71Sopenharmony_ci } 263e41f4b71Sopenharmony_ci ``` 264e41f4b71Sopenharmony_ci 265e41f4b71Sopenharmony_ci- 当装饰的变量是嵌套类或对象数组时,\@Param无法观察深层对象属性的变化。对深层对象属性的观测依赖\@ObservedV2与\@Trace装饰器。 266e41f4b71Sopenharmony_ci 267e41f4b71Sopenharmony_ci ```ts 268e41f4b71Sopenharmony_ci @ObservedV2 269e41f4b71Sopenharmony_ci class Region { 270e41f4b71Sopenharmony_ci @Trace x: number; 271e41f4b71Sopenharmony_ci @Trace y: number; 272e41f4b71Sopenharmony_ci constructor(x: number, y: number) { 273e41f4b71Sopenharmony_ci this.x = x; 274e41f4b71Sopenharmony_ci this.y = y; 275e41f4b71Sopenharmony_ci } 276e41f4b71Sopenharmony_ci } 277e41f4b71Sopenharmony_ci @ObservedV2 278e41f4b71Sopenharmony_ci class Info { 279e41f4b71Sopenharmony_ci @Trace region: Region; 280e41f4b71Sopenharmony_ci @Trace name: string; 281e41f4b71Sopenharmony_ci constructor(name: string, x: number, y: number) { 282e41f4b71Sopenharmony_ci this.name = name; 283e41f4b71Sopenharmony_ci this.region = new Region(x, y); 284e41f4b71Sopenharmony_ci } 285e41f4b71Sopenharmony_ci } 286e41f4b71Sopenharmony_ci @Entry 287e41f4b71Sopenharmony_ci @ComponentV2 288e41f4b71Sopenharmony_ci struct Index { 289e41f4b71Sopenharmony_ci @Local infoArr: Info[] = [new Info("Ocean", 28, 120), new Info("Mountain", 26, 20)]; 290e41f4b71Sopenharmony_ci @Local originInfo: Info = new Info("Origin", 0, 0); 291e41f4b71Sopenharmony_ci build() { 292e41f4b71Sopenharmony_ci Column() { 293e41f4b71Sopenharmony_ci ForEach(this.infoArr, (info: Info) => { 294e41f4b71Sopenharmony_ci Row() { 295e41f4b71Sopenharmony_ci Text(`name: ${info.name}`) 296e41f4b71Sopenharmony_ci Text(`region: ${info.region.x}-${info.region.y}`) 297e41f4b71Sopenharmony_ci } 298e41f4b71Sopenharmony_ci }) 299e41f4b71Sopenharmony_ci Row() { 300e41f4b71Sopenharmony_ci Text(`Origin name: ${this.originInfo.name}`) 301e41f4b71Sopenharmony_ci Text(`Origin region: ${this.originInfo.region.x}-${this.originInfo.region.y}`) 302e41f4b71Sopenharmony_ci } 303e41f4b71Sopenharmony_ci Button("change infoArr item") 304e41f4b71Sopenharmony_ci .onClick(() => { 305e41f4b71Sopenharmony_ci // 由于属性name被@Trace装饰,所以能够观察到 306e41f4b71Sopenharmony_ci this.infoArr[0].name = "Win"; 307e41f4b71Sopenharmony_ci }) 308e41f4b71Sopenharmony_ci Button("change originInfo") 309e41f4b71Sopenharmony_ci .onClick(() => { 310e41f4b71Sopenharmony_ci // 由于变量originInfo被@Local装饰,所以能够观察到 311e41f4b71Sopenharmony_ci this.originInfo = new Info("Origin", 100, 100); 312e41f4b71Sopenharmony_ci }) 313e41f4b71Sopenharmony_ci Button("change originInfo region") 314e41f4b71Sopenharmony_ci .onClick(() => { 315e41f4b71Sopenharmony_ci // 由于属性x、y被@Trace装饰,所以能够观察到 316e41f4b71Sopenharmony_ci this.originInfo.region.x = 25; 317e41f4b71Sopenharmony_ci this.originInfo.region.y = 25; 318e41f4b71Sopenharmony_ci }) 319e41f4b71Sopenharmony_ci } 320e41f4b71Sopenharmony_ci } 321e41f4b71Sopenharmony_ci } 322e41f4b71Sopenharmony_ci @ComponentV2 323e41f4b71Sopenharmony_ci struct Child { 324e41f4b71Sopenharmony_ci @Param infoArr: Info[] = []; 325e41f4b71Sopenharmony_ci @Param originInfo: Info = new Info("O", 0, 0); 326e41f4b71Sopenharmony_ci 327e41f4b71Sopenharmony_ci build() { 328e41f4b71Sopenharmony_ci Column() { 329e41f4b71Sopenharmony_ci ForEach(this.infoArr, (info: Info) => { 330e41f4b71Sopenharmony_ci Row() { 331e41f4b71Sopenharmony_ci Text(`name: ${info.name}`) 332e41f4b71Sopenharmony_ci Text(`region: ${info.region.x}-${info.region.y}`) 333e41f4b71Sopenharmony_ci } 334e41f4b71Sopenharmony_ci }) 335e41f4b71Sopenharmony_ci Row() { 336e41f4b71Sopenharmony_ci Text(`Origin name: ${this.originInfo.name}`) 337e41f4b71Sopenharmony_ci Text(`Origin region: ${this.originInfo.region.x}-${this.originInfo.region.y}`) 338e41f4b71Sopenharmony_ci } 339e41f4b71Sopenharmony_ci } 340e41f4b71Sopenharmony_ci } 341e41f4b71Sopenharmony_ci } 342e41f4b71Sopenharmony_ci ``` 343e41f4b71Sopenharmony_ci 344e41f4b71Sopenharmony_ci- 当装饰的变量类型是内置类型时,可以观察到变量整体赋值以及通过API调用带来的变化。 345e41f4b71Sopenharmony_ci 346e41f4b71Sopenharmony_ci | 类型 | 可观测变化的API | 347e41f4b71Sopenharmony_ci | ----- | ------------------------------------------------------------ | 348e41f4b71Sopenharmony_ci | Array | push、pop、shift、unshift、splice、copyWithin、fill、reverse、sort | 349e41f4b71Sopenharmony_ci | Date | setFullYear, setMonth, setDate, setHours, setMinutes, setSeconds, setMilliseconds, setTime, setUTCFullYear, setUTCMonth, setUTCDate, setUTCHours, setUTCMinutes, setUTCSeconds, setUTCMilliseconds | 350e41f4b71Sopenharmony_ci | Map | set, clear, delete | 351e41f4b71Sopenharmony_ci | Set | add, clear, delete | 352e41f4b71Sopenharmony_ci 353e41f4b71Sopenharmony_ci## 限制条件 354e41f4b71Sopenharmony_ci 355e41f4b71Sopenharmony_ci\@Param装饰器存在以下使用限制: 356e41f4b71Sopenharmony_ci 357e41f4b71Sopenharmony_ci- \@Param装饰器只能在\@ComponentV2装饰器的自定义组件中使用。 358e41f4b71Sopenharmony_ci 359e41f4b71Sopenharmony_ci ```ts 360e41f4b71Sopenharmony_ci @ComponentV2 361e41f4b71Sopenharmony_ci struct CompA { 362e41f4b71Sopenharmony_ci @Param message: string = "Hello World"; // 正确用法 363e41f4b71Sopenharmony_ci build() { 364e41f4b71Sopenharmony_ci } 365e41f4b71Sopenharmony_ci } 366e41f4b71Sopenharmony_ci @Component 367e41f4b71Sopenharmony_ci struct CompB { 368e41f4b71Sopenharmony_ci @Param message: string = "Hello World"; // 错误用法 369e41f4b71Sopenharmony_ci build() { 370e41f4b71Sopenharmony_ci } 371e41f4b71Sopenharmony_ci } 372e41f4b71Sopenharmony_ci ``` 373e41f4b71Sopenharmony_ci 374e41f4b71Sopenharmony_ci- \@Param装饰的变量表示组件外部输入,需要被初始化。支持使用本地初始值做初始化。当存在外部传入值时,将优先使用外部传入的值初始化。既不使用本地初始值,也不使用外部传入值是不允许的。 375e41f4b71Sopenharmony_ci 376e41f4b71Sopenharmony_ci ```ts 377e41f4b71Sopenharmony_ci @ComponentV2 378e41f4b71Sopenharmony_ci struct CompA { 379e41f4b71Sopenharmony_ci @Param param1: string = "Initialize local"; 380e41f4b71Sopenharmony_ci @Param param2: string = "Initialize local and put in"; 381e41f4b71Sopenharmony_ci @Require @Param param3: string; 382e41f4b71Sopenharmony_ci build() { 383e41f4b71Sopenharmony_ci Column() { 384e41f4b71Sopenharmony_ci Text(`${this.param1}`) // Initialize local 385e41f4b71Sopenharmony_ci Text(`${this.param2}`) // Put in 386e41f4b71Sopenharmony_ci Text(`${this.param3}`) // Put in 387e41f4b71Sopenharmony_ci } 388e41f4b71Sopenharmony_ci } 389e41f4b71Sopenharmony_ci } 390e41f4b71Sopenharmony_ci @Entry 391e41f4b71Sopenharmony_ci @ComponentV2 392e41f4b71Sopenharmony_ci struct CompB { 393e41f4b71Sopenharmony_ci @Local message: string = "Put in"; 394e41f4b71Sopenharmony_ci build() { 395e41f4b71Sopenharmony_ci Column() { 396e41f4b71Sopenharmony_ci CompA({ 397e41f4b71Sopenharmony_ci param2: this.message, 398e41f4b71Sopenharmony_ci param3: this.message 399e41f4b71Sopenharmony_ci }) 400e41f4b71Sopenharmony_ci } 401e41f4b71Sopenharmony_ci } 402e41f4b71Sopenharmony_ci } 403e41f4b71Sopenharmony_ci ``` 404e41f4b71Sopenharmony_ci 405e41f4b71Sopenharmony_ci- \@Param装饰的变量在子组件中无法进行修改。但当装饰的变量类型为对象时,在子组件中修改对象中属性是允许的。 406e41f4b71Sopenharmony_ci 407e41f4b71Sopenharmony_ci ```ts 408e41f4b71Sopenharmony_ci @ObservedV2 409e41f4b71Sopenharmony_ci class Info { 410e41f4b71Sopenharmony_ci @Trace name: string; 411e41f4b71Sopenharmony_ci constructor(name: string) { 412e41f4b71Sopenharmony_ci this.name = name; 413e41f4b71Sopenharmony_ci } 414e41f4b71Sopenharmony_ci } 415e41f4b71Sopenharmony_ci @Entry 416e41f4b71Sopenharmony_ci @ComponentV2 417e41f4b71Sopenharmony_ci struct Index { 418e41f4b71Sopenharmony_ci @Local info: Info = new Info("Tom"); 419e41f4b71Sopenharmony_ci build() { 420e41f4b71Sopenharmony_ci Column() { 421e41f4b71Sopenharmony_ci Text(`Parent info.name ${this.info.name}`) 422e41f4b71Sopenharmony_ci Button("Parent change info") 423e41f4b71Sopenharmony_ci .onClick(() => { 424e41f4b71Sopenharmony_ci this.info = new Info("Lucy"); // 父组件更改@Local变量,会同步子组件对应@Param变量 425e41f4b71Sopenharmony_ci }) 426e41f4b71Sopenharmony_ci Child({ info: this.info }) 427e41f4b71Sopenharmony_ci } 428e41f4b71Sopenharmony_ci } 429e41f4b71Sopenharmony_ci } 430e41f4b71Sopenharmony_ci @ComponentV2 431e41f4b71Sopenharmony_ci struct Child { 432e41f4b71Sopenharmony_ci @Require @Param info: Info; 433e41f4b71Sopenharmony_ci build() { 434e41f4b71Sopenharmony_ci Column() { 435e41f4b71Sopenharmony_ci Text(`info.name: ${this.info.name}`) 436e41f4b71Sopenharmony_ci Button("change info") 437e41f4b71Sopenharmony_ci .onClick(() => { 438e41f4b71Sopenharmony_ci this.info = new Info("Jack"); //错误用法,不允许在子组件更改@Param变量 439e41f4b71Sopenharmony_ci }) 440e41f4b71Sopenharmony_ci Button("Child change info.name") 441e41f4b71Sopenharmony_ci .onClick(() => { 442e41f4b71Sopenharmony_ci this.info.name = "Jack"; // 允许在子组件中更改对象中属性 443e41f4b71Sopenharmony_ci }) 444e41f4b71Sopenharmony_ci } 445e41f4b71Sopenharmony_ci } 446e41f4b71Sopenharmony_ci } 447e41f4b71Sopenharmony_ci ``` 448e41f4b71Sopenharmony_ci 449e41f4b71Sopenharmony_ci## 使用场景 450e41f4b71Sopenharmony_ci 451e41f4b71Sopenharmony_ci### 从父组件到子组件变量传递与同步 452e41f4b71Sopenharmony_ci 453e41f4b71Sopenharmony_ci\@Param能够接受父组件\@Local或\@Param传递的数据并与之变化同步。 454e41f4b71Sopenharmony_ci 455e41f4b71Sopenharmony_ci```ts 456e41f4b71Sopenharmony_ci@ObservedV2 457e41f4b71Sopenharmony_ciclass Region { 458e41f4b71Sopenharmony_ci @Trace x: number; 459e41f4b71Sopenharmony_ci @Trace y: number; 460e41f4b71Sopenharmony_ci constructor(x: number, y: number) { 461e41f4b71Sopenharmony_ci this.x = x; 462e41f4b71Sopenharmony_ci this.y = y; 463e41f4b71Sopenharmony_ci } 464e41f4b71Sopenharmony_ci} 465e41f4b71Sopenharmony_ci@ObservedV2 466e41f4b71Sopenharmony_ciclass Info { 467e41f4b71Sopenharmony_ci @Trace name: string; 468e41f4b71Sopenharmony_ci @Trace age: number; 469e41f4b71Sopenharmony_ci @Trace region: Region; 470e41f4b71Sopenharmony_ci constructor(name: string, age: number, x: number, y: number) { 471e41f4b71Sopenharmony_ci this.name = name; 472e41f4b71Sopenharmony_ci this.age = age; 473e41f4b71Sopenharmony_ci this.region = new Region(x, y); 474e41f4b71Sopenharmony_ci } 475e41f4b71Sopenharmony_ci} 476e41f4b71Sopenharmony_ci@Entry 477e41f4b71Sopenharmony_ci@ComponentV2 478e41f4b71Sopenharmony_cistruct Index { 479e41f4b71Sopenharmony_ci @Local infoList: Info[] = [new Info("Alice", 8, 0, 0), new Info("Barry", 10, 1, 20), new Info("Cindy", 18, 24, 40)]; 480e41f4b71Sopenharmony_ci build() { 481e41f4b71Sopenharmony_ci Column() { 482e41f4b71Sopenharmony_ci ForEach(this.infoList, (info: Info) => { 483e41f4b71Sopenharmony_ci MiddleComponent({ info: info }) 484e41f4b71Sopenharmony_ci }) 485e41f4b71Sopenharmony_ci Button("change") 486e41f4b71Sopenharmony_ci .onClick(() => { 487e41f4b71Sopenharmony_ci this.infoList[0] = new Info("Atom", 40, 27, 90); 488e41f4b71Sopenharmony_ci this.infoList[1].name = "Bob"; 489e41f4b71Sopenharmony_ci this.infoList[2].region = new Region(7, 9); 490e41f4b71Sopenharmony_ci }) 491e41f4b71Sopenharmony_ci } 492e41f4b71Sopenharmony_ci } 493e41f4b71Sopenharmony_ci} 494e41f4b71Sopenharmony_ci@ComponentV2 495e41f4b71Sopenharmony_cistruct MiddleComponent { 496e41f4b71Sopenharmony_ci @Require @Param info: Info; 497e41f4b71Sopenharmony_ci build() { 498e41f4b71Sopenharmony_ci Column() { 499e41f4b71Sopenharmony_ci Text(`name: ${this.info.name}`) 500e41f4b71Sopenharmony_ci Text(`age: ${this.info.age}`) 501e41f4b71Sopenharmony_ci SubComponent({ region: this.info.region }) 502e41f4b71Sopenharmony_ci } 503e41f4b71Sopenharmony_ci } 504e41f4b71Sopenharmony_ci} 505e41f4b71Sopenharmony_ci@ComponentV2 506e41f4b71Sopenharmony_cistruct SubComponent { 507e41f4b71Sopenharmony_ci @Require @Param region: Region; 508e41f4b71Sopenharmony_ci build() { 509e41f4b71Sopenharmony_ci Column() { 510e41f4b71Sopenharmony_ci Text(`region: ${this.region.x}-${this.region.y}`) 511e41f4b71Sopenharmony_ci } 512e41f4b71Sopenharmony_ci } 513e41f4b71Sopenharmony_ci} 514e41f4b71Sopenharmony_ci``` 515e41f4b71Sopenharmony_ci 516e41f4b71Sopenharmony_ci### 装饰Date类型变量 517e41f4b71Sopenharmony_ci 518e41f4b71Sopenharmony_ci\@Param装饰Date类型变量,可以观察到数据源对Date整体的赋值,以及调用Date的接口`setFullYear`, `setMonth`, `setDate`, `setHours`, `setMinutes`, `setSeconds`, `setMilliseconds`, `setTime`, `setUTCFullYear`, `setUTCMonth`, `setUTCDate`, `setUTCHours`, `setUTCMinutes`, `setUTCSeconds`, `setUTCMilliseconds` 带来的变化。 519e41f4b71Sopenharmony_ci 520e41f4b71Sopenharmony_ci```ts 521e41f4b71Sopenharmony_ci@ComponentV2 522e41f4b71Sopenharmony_cistruct DateComponent { 523e41f4b71Sopenharmony_ci @Param selectedDate: Date = new Date('2024-01-01'); 524e41f4b71Sopenharmony_ci 525e41f4b71Sopenharmony_ci build() { 526e41f4b71Sopenharmony_ci Column() { 527e41f4b71Sopenharmony_ci DatePicker({ 528e41f4b71Sopenharmony_ci start: new Date('1970-1-1'), 529e41f4b71Sopenharmony_ci end: new Date('2100-1-1'), 530e41f4b71Sopenharmony_ci selected: this.selectedDate 531e41f4b71Sopenharmony_ci }) 532e41f4b71Sopenharmony_ci } 533e41f4b71Sopenharmony_ci } 534e41f4b71Sopenharmony_ci} 535e41f4b71Sopenharmony_ci 536e41f4b71Sopenharmony_ci@Entry 537e41f4b71Sopenharmony_ci@ComponentV2 538e41f4b71Sopenharmony_cistruct ParentComponent { 539e41f4b71Sopenharmony_ci @Local parentSelectedDate: Date = new Date('2021-08-08'); 540e41f4b71Sopenharmony_ci 541e41f4b71Sopenharmony_ci build() { 542e41f4b71Sopenharmony_ci Column() { 543e41f4b71Sopenharmony_ci Button('parent update the new date') 544e41f4b71Sopenharmony_ci .margin(10) 545e41f4b71Sopenharmony_ci .onClick(() => { 546e41f4b71Sopenharmony_ci this.parentSelectedDate = new Date('2023-07-07') 547e41f4b71Sopenharmony_ci }) 548e41f4b71Sopenharmony_ci Button('increase the year by 1') 549e41f4b71Sopenharmony_ci .margin(10) 550e41f4b71Sopenharmony_ci .onClick(() => { 551e41f4b71Sopenharmony_ci this.parentSelectedDate.setFullYear(this.parentSelectedDate.getFullYear() + 1) 552e41f4b71Sopenharmony_ci }) 553e41f4b71Sopenharmony_ci Button('increase the month by 1') 554e41f4b71Sopenharmony_ci .margin(10) 555e41f4b71Sopenharmony_ci .onClick(() => { 556e41f4b71Sopenharmony_ci this.parentSelectedDate.setMonth(this.parentSelectedDate.getMonth() + 1) 557e41f4b71Sopenharmony_ci }) 558e41f4b71Sopenharmony_ci Button('parent increase the day by 1') 559e41f4b71Sopenharmony_ci .margin(10) 560e41f4b71Sopenharmony_ci .onClick(() => { 561e41f4b71Sopenharmony_ci this.parentSelectedDate.setDate(this.parentSelectedDate.getDate() + 1) 562e41f4b71Sopenharmony_ci }) 563e41f4b71Sopenharmony_ci DateComponent({ selectedDate: this.parentSelectedDate }) 564e41f4b71Sopenharmony_ci } 565e41f4b71Sopenharmony_ci } 566e41f4b71Sopenharmony_ci} 567e41f4b71Sopenharmony_ci``` 568e41f4b71Sopenharmony_ci 569e41f4b71Sopenharmony_ci### 装饰Map类型变量 570e41f4b71Sopenharmony_ci 571e41f4b71Sopenharmony_ci\@Param装饰Map类型变量,可以观察到数据源对Map整体的赋值,以及调用Map的接口 set、clear、delete带来的变化。 572e41f4b71Sopenharmony_ci 573e41f4b71Sopenharmony_ci```ts 574e41f4b71Sopenharmony_ci@ComponentV2 575e41f4b71Sopenharmony_cistruct Child { 576e41f4b71Sopenharmony_ci @Param value: Map<number, string> = new Map() 577e41f4b71Sopenharmony_ci 578e41f4b71Sopenharmony_ci build() { 579e41f4b71Sopenharmony_ci Column() { 580e41f4b71Sopenharmony_ci ForEach(Array.from(this.value.entries()), (item: [number, string]) => { 581e41f4b71Sopenharmony_ci Text(`${item[0]}`).fontSize(30) 582e41f4b71Sopenharmony_ci Text(`${item[1]}`).fontSize(30) 583e41f4b71Sopenharmony_ci Divider() 584e41f4b71Sopenharmony_ci }) 585e41f4b71Sopenharmony_ci } 586e41f4b71Sopenharmony_ci } 587e41f4b71Sopenharmony_ci} 588e41f4b71Sopenharmony_ci@Entry 589e41f4b71Sopenharmony_ci@ComponentV2 590e41f4b71Sopenharmony_cistruct MapSample2 { 591e41f4b71Sopenharmony_ci @Local message: Map<number, string> = new Map([[0, "a"], [1, "b"], [3, "c"]]) 592e41f4b71Sopenharmony_ci 593e41f4b71Sopenharmony_ci build() { 594e41f4b71Sopenharmony_ci Row() { 595e41f4b71Sopenharmony_ci Column() { 596e41f4b71Sopenharmony_ci Child({ value: this.message }) 597e41f4b71Sopenharmony_ci Button('init map').onClick(() => { 598e41f4b71Sopenharmony_ci this.message = new Map([[0, "a"], [1, "b"], [3, "c"]]) 599e41f4b71Sopenharmony_ci }) 600e41f4b71Sopenharmony_ci Button('set new one').onClick(() => { 601e41f4b71Sopenharmony_ci this.message.set(4, "d") 602e41f4b71Sopenharmony_ci }) 603e41f4b71Sopenharmony_ci Button('clear').onClick(() => { 604e41f4b71Sopenharmony_ci this.message.clear() 605e41f4b71Sopenharmony_ci }) 606e41f4b71Sopenharmony_ci Button('replace the first one').onClick(() => { 607e41f4b71Sopenharmony_ci this.message.set(0, "aa") 608e41f4b71Sopenharmony_ci }) 609e41f4b71Sopenharmony_ci Button('delete the first one').onClick(() => { 610e41f4b71Sopenharmony_ci this.message.delete(0) 611e41f4b71Sopenharmony_ci }) 612e41f4b71Sopenharmony_ci } 613e41f4b71Sopenharmony_ci .width('100%') 614e41f4b71Sopenharmony_ci } 615e41f4b71Sopenharmony_ci .height('100%') 616e41f4b71Sopenharmony_ci } 617e41f4b71Sopenharmony_ci} 618e41f4b71Sopenharmony_ci``` 619e41f4b71Sopenharmony_ci 620e41f4b71Sopenharmony_ci### 装饰Set类型变量 621e41f4b71Sopenharmony_ci 622e41f4b71Sopenharmony_ci\@Param装饰Set类型变量,可以观察到数据源对Set整体的赋值,以及调用Set的接口 add、clear、delete带来的变化。 623e41f4b71Sopenharmony_ci 624e41f4b71Sopenharmony_ci```ts 625e41f4b71Sopenharmony_ci@ComponentV2 626e41f4b71Sopenharmony_cistruct Child { 627e41f4b71Sopenharmony_ci @Param message: Set<number> = new Set() 628e41f4b71Sopenharmony_ci 629e41f4b71Sopenharmony_ci build() { 630e41f4b71Sopenharmony_ci Column() { 631e41f4b71Sopenharmony_ci ForEach(Array.from(this.message.entries()), (item: [number, string]) => { 632e41f4b71Sopenharmony_ci Text(`${item[0]}`).fontSize(30) 633e41f4b71Sopenharmony_ci Divider() 634e41f4b71Sopenharmony_ci }) 635e41f4b71Sopenharmony_ci } 636e41f4b71Sopenharmony_ci .width('100%') 637e41f4b71Sopenharmony_ci } 638e41f4b71Sopenharmony_ci} 639e41f4b71Sopenharmony_ci@Entry 640e41f4b71Sopenharmony_ci@ComponentV2 641e41f4b71Sopenharmony_cistruct SetSample11 { 642e41f4b71Sopenharmony_ci @Local message: Set<number> = new Set([0, 1, 2, 3, 4]) 643e41f4b71Sopenharmony_ci 644e41f4b71Sopenharmony_ci build() { 645e41f4b71Sopenharmony_ci Row() { 646e41f4b71Sopenharmony_ci Column() { 647e41f4b71Sopenharmony_ci Child({ message: this.message }) 648e41f4b71Sopenharmony_ci Button('init set').onClick(() => { 649e41f4b71Sopenharmony_ci this.message = new Set([0, 1, 2, 3, 4]) 650e41f4b71Sopenharmony_ci }) 651e41f4b71Sopenharmony_ci Button('set new one').onClick(() => { 652e41f4b71Sopenharmony_ci this.message.add(5) 653e41f4b71Sopenharmony_ci }) 654e41f4b71Sopenharmony_ci Button('clear').onClick(() => { 655e41f4b71Sopenharmony_ci this.message.clear() 656e41f4b71Sopenharmony_ci }) 657e41f4b71Sopenharmony_ci Button('delete the first one').onClick(() => { 658e41f4b71Sopenharmony_ci this.message.delete(0) 659e41f4b71Sopenharmony_ci }) 660e41f4b71Sopenharmony_ci } 661e41f4b71Sopenharmony_ci .width('100%') 662e41f4b71Sopenharmony_ci } 663e41f4b71Sopenharmony_ci .height('100%') 664e41f4b71Sopenharmony_ci } 665e41f4b71Sopenharmony_ci} 666e41f4b71Sopenharmony_ci``` 667e41f4b71Sopenharmony_ci 668e41f4b71Sopenharmony_ci### 联合类型 669e41f4b71Sopenharmony_ci 670e41f4b71Sopenharmony_ci\@Param支持null、undefined以及联合类型。在下面的示例中,count类型为number | undefined,点击改变count的类型,UI会随之刷新。 671e41f4b71Sopenharmony_ci 672e41f4b71Sopenharmony_ci```ts 673e41f4b71Sopenharmony_ci@Entry 674e41f4b71Sopenharmony_ci@ComponentV2 675e41f4b71Sopenharmony_cistruct Index { 676e41f4b71Sopenharmony_ci @Local count: number | undefined = 0; 677e41f4b71Sopenharmony_ci 678e41f4b71Sopenharmony_ci build() { 679e41f4b71Sopenharmony_ci Column() { 680e41f4b71Sopenharmony_ci MyComponent({ count: this.count }) 681e41f4b71Sopenharmony_ci Button('change') 682e41f4b71Sopenharmony_ci .onClick(() => { 683e41f4b71Sopenharmony_ci this.count = undefined; 684e41f4b71Sopenharmony_ci }) 685e41f4b71Sopenharmony_ci } 686e41f4b71Sopenharmony_ci } 687e41f4b71Sopenharmony_ci} 688e41f4b71Sopenharmony_ci 689e41f4b71Sopenharmony_ci@ComponentV2 690e41f4b71Sopenharmony_cistruct MyComponent { 691e41f4b71Sopenharmony_ci @Param count: number | undefined = 0; 692e41f4b71Sopenharmony_ci 693e41f4b71Sopenharmony_ci build() { 694e41f4b71Sopenharmony_ci Column() { 695e41f4b71Sopenharmony_ci Text(`count(${this.count})`) 696e41f4b71Sopenharmony_ci } 697e41f4b71Sopenharmony_ci } 698e41f4b71Sopenharmony_ci} 699e41f4b71Sopenharmony_ci```