1# \@Event装饰器:组件输出 2 3为了实现子组件向父组件要求更新\@Param装饰变量的能力,开发者可以使用\@Event装饰器。 4 5>**说明:** 6> 7>从API version 12开始,在\@ComponentV2装饰的自定义组件中支持使用\@Event装饰器。 8> 9>当前状态管理(V2试用版)仍在逐步开发中,相关功能尚未成熟,建议开发者尝鲜试用。 10 11## 概述 12 13由于\@Param装饰的变量在本地无法更改,使用\@Event装饰器装饰回调方法并调用,可以实现更改数据源的变量,再通过\@Local的同步机制,将修改同步回\@Param,以此达到主动更新\@Param装饰变量的效果。 14 15\@Event用于装饰组件对外输出的方法: 16 17- \@Event装饰的回调方法中参数以及返回值由开发者决定。 18 19- \@Event装饰非回调类型的变量不会生效。当\@Event没有初始化时,会自动生成一个空的函数作为默认回调。 20- 当\@Event未被外部初始化,但本地有默认值时,会使用本地默认的函数进行处理。 21 22\@Param标志着组件的输入,表明该变量受父组件影响,而\@Event标志着组件的输出,可以通过该方法影响父组件。使用\@Event装饰回调方法是一种规范,表明该回调作为自定义组件的输出。父组件需要判断是否提供对应方法用于子组件更改\@Param变量的数据源。 23 24## 装饰器说明 25 26| \@Event属性装饰器 | 说明 | 27| ------------------- | ------------------------------------------------------------ | 28| 装饰器参数 | 无。 | 29| 允许装饰的变量类型 | 回调方法,例如()=>void、(x:number)=>boolean等。回调方法是否含有参数以及返回值由开发者决定。 | 30| 允许传入的函数类型 | 箭头函数。 | 31 32## 限制条件 33 34- \@Event只能用在\@ComponentV2装饰的自定义组件中。当装饰非方法类型的变量时,不会有任何作用。 35 36 ```ts 37 @ComponentV2 38 struct Index { 39 @Event changeFactory: ()=>void = ()=>{}; //正确用法 40 @Event message: string = "abcd"; // 错误用法,装饰非方法类型变量 41 } 42 @Component 43 struct CompA { 44 @Event changeFactory: ()=>void = ()=>{}; // 错误用法 45 } 46 ``` 47 48 49## 使用场景 50 51### 更改父组件中变量 52 53使用\@Event可以更改父组件中变量,当该变量作为子组件\@Param变量的数据源时,该变化会同步回子组件的\@Param变量。 54 55```ts 56@Entry 57@ComponentV2 58struct Index { 59 @Local title: string = "Titile One"; 60 @Local fontColor: Color = Color.Red; 61 62 build() { 63 Column() { 64 Child({ 65 title: this.title, 66 fontColor: this.fontColor, 67 changeFactory: (type: number) => { 68 if (type == 1) { 69 this.title = "Title One"; 70 this.fontColor = Color.Red; 71 } else if (type == 2) { 72 this.title = "Title Two"; 73 this.fontColor = Color.Green; 74 } 75 } 76 }) 77 } 78 } 79} 80 81@ComponentV2 82struct Child { 83 @Param title: string = ''; 84 @Param fontColor: Color = Color.Black; 85 @Event changeFactory: (x: number) => void = (x: number) => {}; 86 87 build() { 88 Column() { 89 Text(`${this.title}`) 90 .fontColor(this.fontColor) 91 Button("change to Title Two") 92 .onClick(() => { 93 this.changeFactory(2); 94 }) 95 Button("change to Title One") 96 .onClick(() => { 97 this.changeFactory(1); 98 }) 99 } 100 } 101} 102``` 103 104值得注意的是,使用\@Event修改父组件的值是立刻生效的,但从父组件将变化同步回子组件的过程是异步的,即在调用完\@Event的方法后,子组件内的值不会立刻变化。这是因为\@Event将子组件值实际的变化能力交由父组件处理,在父组件实际决定如何处理后,将最终值在渲染之前同步回子组件。 105 106```ts 107@ComponentV2 108struct Child { 109 @Param index: number = 0; 110 @Event changeIndex: (val: number) => void; 111 112 build() { 113 Column() { 114 Text(`Child index: ${this.index}`) 115 .onClick(() => { 116 this.changeIndex(20); 117 console.log(`after changeIndex ${this.index}`); 118 }) 119 } 120 } 121} 122@Entry 123@ComponentV2 124struct Index { 125 @Local index: number = 0; 126 127 build() { 128 Column() { 129 Child({ 130 index: this.index, 131 changeIndex: (val: number) => { 132 this.index = val; 133 console.log(`in changeIndex ${this.index}`); 134 } 135 }) 136 } 137 } 138} 139``` 140 141在上面的示例中,点击文字触发\@Event函数事件改变子组件的值,打印出的日志为: 142 143``` 144in changeIndex 20 145after changeIndex 0 146``` 147 148这表明在调用changeIndex之后,父组件中index的值已经变化,但子组件中的index值还没有同步变化。