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