android2harmony 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/agents/scripts/hmos-precheck/index.mjs +0 -8
  2. package/agents/self-tester.md +339 -0
  3. package/dist/index.js +635 -77
  4. package/dist/index.js.map +4 -4
  5. package/package.json +37 -29
  6. package/skills/hmos-incremental-ui-align/README.md +251 -0
  7. package/skills/hmos-incremental-ui-align/SKILL.md +365 -0
  8. package/skills/hmos-incremental-ui-align/diff_analysis.md +53 -0
  9. package/skills/hmos-incremental-ui-align/page_align.md +62 -0
  10. package/skills/hmos-incremental-ui-align/references/Comparison_Template.md +38 -0
  11. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Link/350/243/205/351/245/260/345/231/250/357/274/232/347/210/266/345/255/220/345/217/214/345/220/221/345/220/214/346/255/245.md +648 -0
  12. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Observed/350/243/205/351/245/260/345/231/250/345/222/214@ObjectLink/350/243/205/351/245/260/345/231/250/357/274/232/345/265/214/345/245/227/347/261/273/345/257/271/350/261/241/345/261/236/346/200/247/345/217/230/345/214/226.md +2089 -0
  13. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Prop/350/243/205/351/245/260/345/231/250/357/274/232/347/210/266/345/255/220/345/215/225/345/220/221/345/220/214/346/255/245.md +1033 -0
  14. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Provide/350/243/205/351/245/260/345/231/250/345/222/214@Consume/350/243/205/351/245/260/345/231/250/357/274/232/344/270/216/345/220/216/344/273/243/347/273/204/344/273/266/345/217/214/345/220/221/345/220/214/346/255/245.md +1183 -0
  15. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@State/350/243/205/351/245/260/345/231/250/357/274/232/347/273/204/344/273/266/345/206/205/347/212/266/346/200/201.md +576 -0
  16. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Track/350/243/205/351/245/260/345/231/250/357/274/232class/345/257/271/350/261/241/345/261/236/346/200/247/347/272/247/346/233/264/346/226/260.md +297 -0
  17. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Watch/350/243/205/351/245/260/345/231/250/357/274/232/347/212/266/346/200/201/345/217/230/351/207/217/346/233/264/346/224/271/351/200/232/347/237/245.md +395 -0
  18. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/AppStorage/357/274/232/345/272/224/347/224/250/345/205/250/345/261/200/347/232/204UI/347/212/266/346/200/201/345/255/230/345/202/250.md +903 -0
  19. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/Environment/357/274/232/350/256/276/345/244/207/347/216/257/345/242/203/346/237/245/350/257/242.md +106 -0
  20. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/LocalStorage/357/274/232/351/241/265/351/235/242/347/272/247UI/347/212/266/346/200/201/345/255/230/345/202/250.md +1178 -0
  21. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/MVVM/346/250/241/345/274/217V1.md +911 -0
  22. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/PersistentStorage/357/274/232/346/214/201/344/271/205/345/214/226/345/255/230/345/202/250UI/347/212/266/346/200/201.md +355 -0
  23. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243//347/256/241/347/220/206/345/272/224/347/224/250/346/213/245/346/234/211/347/232/204/347/212/266/346/200/201/346/246/202/350/277/260.md +11 -0
  24. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/!!/350/257/255/346/263/225/357/274/232/345/217/214/345/220/221/347/273/221/345/256/232.md +206 -0
  25. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/@Computed/350/243/205/351/245/260/345/231/250/357/274/232/350/256/241/347/256/227/345/261/236/346/200/247.md +373 -0
  26. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/@Event/350/243/205/351/245/260/345/231/250/357/274/232/350/247/204/350/214/203/347/273/204/344/273/266/350/276/223/345/207/272.md +158 -0
  27. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/@Local/350/243/205/351/245/260/345/231/250/357/274/232/347/273/204/344/273/266/345/206/205/351/203/250/347/212/266/346/200/201.md +750 -0
  28. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/@Monitor/350/243/205/351/245/260/345/231/250/357/274/232/347/212/266/346/200/201/345/217/230/351/207/217/344/277/256/346/224/271/345/274/202/346/255/245/347/233/221/345/220/254.md +1704 -0
  29. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/@ObservedV2/350/243/205/351/245/260/345/231/250/345/222/214@Trace/350/243/205/351/245/260/345/231/250/357/274/232/347/261/273/345/261/236/346/200/247/345/217/230/345/214/226/350/247/202/346/265/213.md +1012 -0
  30. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/@Once/350/243/205/351/245/260/345/231/250/357/274/232/345/210/235/345/247/213/345/214/226/345/220/214/346/255/245/344/270/200/346/254/241.md +164 -0
  31. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/@Param/350/243/205/351/245/260/345/231/250/357/274/232/347/273/204/344/273/266/345/244/226/351/203/250/350/276/223/345/205/245.md +840 -0
  32. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/@Provider/350/243/205/351/245/260/345/231/250/345/222/214@Consumer/350/243/205/351/245/260/345/231/250/357/274/232/350/267/250/347/273/204/344/273/266/345/261/202/347/272/247/345/217/214/345/220/221/345/220/214/346/255/245.md +856 -0
  33. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/@Type/350/243/205/351/245/260/345/231/250/357/274/232/346/240/207/350/256/260/347/261/273/345/261/236/346/200/247/347/232/204/347/261/273/345/236/213.md +83 -0
  34. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/AppStorageV2/357/274/232/345/272/224/347/224/250/345/205/250/345/261/200UI/347/212/266/346/200/201/345/255/230/345/202/250.md +294 -0
  35. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/MVVM/346/250/241/345/274/217/357/274/210V2/357/274/211.md +1407 -0
  36. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/PersistenceV2/357/274/232/346/214/201/344/271/205/345/214/226/345/255/230/345/202/250UI/347/212/266/346/200/201.md +1220 -0
  37. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/_/350/214/203/345/274/217/351/200/211/346/213/251/350/257/264/346/230/216.md +47 -0
  38. package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2//347/212/266/346/200/201/347/256/241/347/220/206V1/345/220/221V2/350/277/201/347/247/273/344/270/216/346/267/267/347/224/250/346/214/207/345/257/274.md +840 -0
  39. package/skills/hmos-incremental-ui-align/references/State_Model_Template.md +74 -0
  40. package/skills/hmos-incremental-ui-align/references/UI_Analysis_Template.md +34 -0
  41. package/skills/hmos-incremental-ui-align/references/android-to-harmonyOS-ui-atomic-component-mapping-reference.md +2533 -0
  42. package/skills/hmos-incremental-ui-align/references/android-to-harmonyOS-ui-interaction-mapping-reference.md +555 -0
  43. package/skills/hmos-incremental-ui-align/references/android-to-harmonyOS-ui-layout-mapping-reference.md +117 -0
  44. package/skills/hmos-incremental-ui-align/scripts/app_feature_verify.ts +999 -0
  45. package/skills/hmos-incremental-ui-align/scripts/extract_checklist.ts +343 -0
  46. package/skills/hmos-incremental-ui-align/scripts/navigation-capure.md +76 -0
  47. package/skills/hmos-incremental-ui-align/scripts/page_capture.ts +977 -0
  48. package/skills/hmos-incremental-ui-align/scripts/page_capture_burst.ts +188 -0
  49. package/skills/hmos-spec-generate/SKILL.md +1 -1
  50. package/tools/autotest/deps/autotest-agent-0.1.1.tgz +0 -0
  51. package/tools/autotest/engine/batch-launcher.ts +326 -0
  52. package/tools/autotest/engine/report-tool.ts +773 -0
  53. package/tools/autotest/engine/self-test-runner.ts +1024 -0
  54. package/tools/autotest/engine/testcases-tool.ts +246 -0
  55. package/tools/autotest/resolve-metadata-tool.ts +143 -0
  56. package/tools/autotest/runner/logger.ts +45 -0
  57. package/tools/autotest/runner/process-utils.ts +41 -0
  58. package/tools/autotest/validate.ts +115 -0
@@ -0,0 +1,373 @@
1
+ # @Computed装饰器:计算属性
2
+
3
+ 当开发者使用相同的计算逻辑重复绑定在UI上时,为了防止重复计算,可以使用@Computed计算属性。计算属性中依赖的状态变量变化时,只会计算一次。这解决了UI多次重用该属性导致的重复计算和性能问题。
4
+
5
+ ```arkts
6
+ @Computed
7
+ get sum() {
8
+ return this.count1 + this.count2 + this.count3;
9
+ }
10
+ ```
11
+
12
+ ```arkts
13
+ Text(`${this.count1 + this.count2 + this.count3}`) // 计算this.count1 + this.count2 + this.count3
14
+ Text(`${this.count1 + this.count2 + this.count3}`) // 重复计算this.count1 + this.count2 + this.count3
15
+ Text(`${this.sum}`) // 读取@Computed sum的缓存值,节省上述重复计算
16
+ Text(`${this.sum}`) // 读取@Computed sum的缓存值,节省上述重复计算
17
+ ```
18
+
19
+ 在阅读本文档前,建议提前阅读:
20
+ - [@ComponentV2](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-create-custom-components)
21
+ - [@ObservedV2和@Trace](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-new-observedv2-and-trace)
22
+ - [@Local](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-new-local)
23
+
24
+ @Computed装饰器从API version 12开始支持。
25
+ 从API version 12开始,该装饰器支持在元服务中使用。
26
+ 从API version 23开始,该装饰器支持在ArkTS卡片中使用。
27
+
28
+ ## 概述
29
+
30
+ @Computed为方法装饰器,装饰getter方法。@Computed会检测被计算的属性变化,当被计算的属性变化时,@Computed只会被求解一次。不建议在@Computed中修改变量,错误的使用会导致数据无法被追踪或appfreeze等问题。
31
+
32
+ 但需要注意,对于简单计算,不建议使用计算属性,因为计算属性本身也有开销。对于复杂的计算,@Computed能带来性能收益。
33
+
34
+ ## 装饰器说明
35
+
36
+ @Computed语法:
37
+ ```arkts
38
+ @Computed
39
+ get varName(): T {
40
+ return value;
41
+ }
42
+ ```
43
+
44
+ | @Computed方法装饰器 | 说明 |
45
+ | --- | --- |
46
+ | 支持类型 | getter访问器。 |
47
+ | 从父组件初始化 | 禁止。 |
48
+ | 可初始化子组件 | [@Param](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-new-param)。 |
49
+ | 被执行的时机 | @ComponentV2中的@Computed会在自定义组件创建的时候初始化,触发@Computed计算。@ObservedV2装饰的类中的@Computed,会在@ObservedV2装饰的类实例创建后,异步初始化,触发@Computed计算。在@Computed中计算的状态变量被改变时,计算属性会重新计算。 |
50
+ | 是否允许赋值 | @Computed装饰的属性是只读的,不允许赋值。 |
51
+
52
+ ## 使用限制
53
+
54
+ 1. @Computed为方法装饰器,仅能装饰getter方法。
55
+ ```arkts
56
+ @Computed
57
+ get fullName() { // 正确用法
58
+ return this.firstName + ' ' + this.lastName;
59
+ }
60
+ @Computed val: number = 0; // 错误用法,编译时报错
61
+ @Computed
62
+ func() { // 错误用法,编译时报错
63
+ }
64
+ ```
65
+
66
+ 2. @Computed装饰的方法只有在初始化,或者其被计算的状态变量改变时,才会发生重新计算。不建议开发者在@Computed装饰的getter方法中做除获取数据外其余的逻辑操作。
67
+ ```arkts
68
+ @Entry
69
+ @ComponentV2
70
+ struct Page {
71
+ @Local firstName: string = 'Hua';
72
+ @Local lastName: string = 'Li';
73
+ @Local showFullNameRequestCount: number = 0;
74
+ private fullNameRequestCount: number = 0;
75
+ @Computed
76
+ get fullName() {
77
+ console.info('fullName');
78
+ // 不建议在@Computed的计算中做赋值逻辑
79
+ this.fullNameRequestCount++;
80
+ return this.firstName + ' ' + this.lastName;
81
+ }
82
+ build() {
83
+ Column() {
84
+ Text(`${this.fullName}`)
85
+ Text(`${this.fullName}`)
86
+ Text(`count ${this.showFullNameRequestCount}`)
87
+ Button('get fullName').onClick(() => {
88
+ this.showFullNameRequestCount = this.fullNameRequestCount;
89
+ })
90
+ }
91
+ }
92
+ }
93
+ ```
94
+
95
+ 3. 在@Computed装饰的getter方法中,不能改变参与计算的属性,以防止重复执行计算属性导致的appfreeze。
96
+ ```arkts
97
+ @Entry
98
+ @ComponentV2
99
+ struct Page {
100
+ @Local firstName: string = 'Hua';
101
+ @Local lastName: string = 'Li';
102
+ @Computed
103
+ get fullName1() {
104
+ console.info('fullName1');
105
+ this.lastName += 'a'; // 错误,不能改变参与计算的属性
106
+ return this.firstName + ' ' + this.lastName;
107
+ }
108
+ @Computed
109
+ get fullName2() {
110
+ console.info('fullName2');
111
+ this.firstName += 'a'; // 错误,不能改变参与计算的属性
112
+ return this.firstName + ' ' + this.lastName;
113
+ }
114
+ build() {
115
+ Column() {
116
+ Text(`${this.fullName1}`)
117
+ Text(`${this.fullName2}`)
118
+ }
119
+ }
120
+ }
121
+ ```
122
+
123
+ 4. @Computed不能和双向绑定!!连用,@Computed装饰的是getter访问器,不会被子组件同步,也不能被赋值。
124
+ ```arkts
125
+ @ComponentV2
126
+ struct Child {
127
+ @Param double: number = 100;
128
+ @Event $double: (val: number) => void;
129
+ build() {
130
+ Button('ChildChange')
131
+ .onClick(() => {
132
+ this.$double(200);
133
+ })
134
+ }
135
+ }
136
+ @Entry
137
+ @ComponentV2
138
+ struct Index {
139
+ @Local count: number = 100;
140
+ @Computed
141
+ get double() {
142
+ return this.count * 2;
143
+ }
144
+ set double(newValue : number) {
145
+ this.count = newValue / 2;
146
+ }
147
+ build() {
148
+ Scroll() {
149
+ Column({ space: 3 }) {
150
+ Text(`${this.count}`)
151
+ Child({ double: this.double!! }) // 错误写法
152
+ }
153
+ }
154
+ }
155
+ }
156
+ ```
157
+
158
+ 5. @Computed为状态管理V2提供的能力,只能在@ComponentV2和@ObservedV2中使用。
159
+
160
+ 6. 多个@Computed一起使用时,警惕循环求解,以防止计算过程中的死循环。
161
+ ```arkts
162
+ @Local a : number = 1;
163
+ @Computed
164
+ get b() {
165
+ return this.a + ' ' + this.c; // 错误写法,存在循环
166
+ }
167
+ @Computed
168
+ get c() {
169
+ return this.a + ' ' + this.b; // 错误写法,存在循环
170
+ }
171
+ ```
172
+
173
+ ## 使用场景
174
+
175
+ ### 当被计算的属性变化时,@Computed装饰的getter访问器只会被求解一次
176
+
177
+ **1. 在自定义组件中使用计算属性**
178
+
179
+ 点击第一个Button改变lastName,触发@Computed fullName重新计算。this.fullName被绑定在两个Text组件上,计算只发生了一次。
180
+
181
+ ```arkts
182
+ import { hilog } from '@kit.PerformanceAnalysisKit';
183
+ const TAG = '[Sample_Textcomponent]';
184
+ const DOMAIN = 0xF811;
185
+ const BUNDLE = 'Textcomponent_';
186
+
187
+ @Entry
188
+ @ComponentV2
189
+ struct CustomComponentUse {
190
+ @Local firstName: string = 'Li';
191
+ @Local lastName: string = 'Hua';
192
+ age: number = 20;
193
+ @Computed
194
+ get fullName() {
195
+ hilog.info(DOMAIN, TAG, BUNDLE + '---------Computed----------');
196
+ return this.firstName + ' ' + this.lastName + this.age;
197
+ }
198
+ build() {
199
+ Column() {
200
+ Text(this.lastName + ' ' + this.firstName)
201
+ Text(this.lastName + ' ' + this.firstName)
202
+ Divider()
203
+ Text(this.fullName)
204
+ Text(this.fullName)
205
+ Button('changed lastName')
206
+ .onClick(() => {
207
+ this.lastName += 'a';
208
+ })
209
+ Button('changed age')
210
+ .onClick(() => {
211
+ this.age++; // 无法触发Computed
212
+ })
213
+ }
214
+ }
215
+ }
216
+ ```
217
+
218
+ 计算属性本身会带来性能开销,在实际应用开发中需要注意:
219
+ - 对于简单的计算逻辑,可以不使用计算属性。
220
+ - 如果计算逻辑在视图中仅使用一次,则不使用计算属性,直接求解。
221
+
222
+ **2. 在@ObservedV2装饰的类中使用计算属性**
223
+
224
+ 点击Button改变lastName,触发@Computed fullName重新计算,且只被计算一次。
225
+
226
+ ```arkts
227
+ import { hilog } from '@kit.PerformanceAnalysisKit';
228
+ const TAG = '[Sample_Textcomponent]';
229
+ const DOMAIN = 0xF811;
230
+ const BUNDLE = 'Textcomponent_';
231
+
232
+ @ObservedV2
233
+ class Name {
234
+ @Trace public firstName: string = 'Hua';
235
+ @Trace public lastName: string = 'Li';
236
+ @Computed
237
+ get fullName() {
238
+ hilog.info(DOMAIN, TAG, BUNDLE + '---------Computed----------');
239
+ return this.firstName + ' ' + this.lastName;
240
+ }
241
+ }
242
+
243
+ const name: Name = new Name();
244
+ @Entry
245
+ @ComponentV2
246
+ struct ObservedV2ClassUser {
247
+ name1: Name = name;
248
+ build() {
249
+ Column() {
250
+ Text(this.name1.fullName)
251
+ Text(this.name1.fullName)
252
+ Button('changed lastName').onClick(() => {
253
+ this.name1.lastName += 'a';
254
+ })
255
+ }
256
+ }
257
+ }
258
+ ```
259
+
260
+ ### @Computed装饰的属性可以被@Monitor监听变化
261
+
262
+ 使用计算属性求解fahrenheit和kelvin:
263
+
264
+ ```arkts
265
+ import { hilog } from '@kit.PerformanceAnalysisKit';
266
+ const TAG = '[Sample_Textcomponent]';
267
+ const DOMAIN = 0xF811;
268
+ const BUNDLE = 'Textcomponent_';
269
+
270
+ @Entry
271
+ @ComponentV2
272
+ struct ComputedPropertyResolution {
273
+ @Local celsius: number = 20;
274
+ @Computed
275
+ get fahrenheit(): number {
276
+ return this.celsius * 9 / 5 + 32;
277
+ }
278
+ @Computed
279
+ get kelvin(): number {
280
+ return (this.fahrenheit - 32) * 5 / 9 + 273.15;
281
+ }
282
+ @Monitor('kelvin')
283
+ onKelvinMonitor(mon: IMonitor) {
284
+ hilog.info(DOMAIN, TAG, BUNDLE + 'kelvin changed from' + mon.value()?.before + ' to ' + mon.value()?.now);
285
+ }
286
+ build() {
287
+ Column({ space: 20 }) {
288
+ Row({ space: 20 }) {
289
+ Button('-')
290
+ .onClick(() => {
291
+ this.celsius--;
292
+ })
293
+ Text(`Celsius ${this.celsius.toFixed(1)}`).fontSize(40)
294
+ Button('+')
295
+ .onClick(() => {
296
+ this.celsius++;
297
+ })
298
+ }
299
+ Text(`Fahrenheit ${this.fahrenheit.toFixed(2)}`).fontSize(40)
300
+ Text(`Kelvin ${this.kelvin.toFixed(2)}`).fontSize(40)
301
+ }
302
+ .width('100%')
303
+ }
304
+ }
305
+ ```
306
+
307
+ ### @Computed装饰的属性可以初始化@Param
308
+
309
+ 使用@Computed初始化@Param:
310
+
311
+ ```arkts
312
+ @ObservedV2
313
+ class Article {
314
+ @Trace public quantity: number = 0;
315
+ public unitPrice: number = 0;
316
+ constructor(quantity: number, unitPrice: number) {
317
+ this.quantity = quantity;
318
+ this.unitPrice = unitPrice;
319
+ }
320
+ }
321
+
322
+ @Entry
323
+ @ComponentV2
324
+ struct ComputingInitParam {
325
+ @Local shoppingBasket: Article[] = [new Article(1, 20), new Article(5, 2)];
326
+ @Computed
327
+ get total(): number {
328
+ return this.shoppingBasket.reduce((acc: number, item: Article) => acc + (item.quantity * item.unitPrice), 0);
329
+ }
330
+ @Computed
331
+ get qualifiesForDiscount(): boolean {
332
+ return this.total >= 100;
333
+ }
334
+ build() {
335
+ Column() {
336
+ Text(`Shopping List: `)
337
+ .fontSize(30)
338
+ ForEach(this.shoppingBasket, (item: Article) => {
339
+ Row() {
340
+ Text(`unitPrice: ${item.unitPrice}`)
341
+ Button('-')
342
+ .onClick(() => {
343
+ if (item.quantity > 0) {
344
+ item.quantity--;
345
+ }
346
+ })
347
+ Text(`quantity: ${item.quantity}`)
348
+ Button('+')
349
+ .onClick(() => {
350
+ item.quantity++;
351
+ })
352
+ }
353
+ Divider()
354
+ })
355
+ Child({ total: this.total, qualifiesForDiscount: this.qualifiesForDiscount })
356
+ }.alignItems(HorizontalAlign.Start)
357
+ }
358
+ }
359
+
360
+ @ComponentV2
361
+ struct Child {
362
+ @Param total: number = 0;
363
+ @Param qualifiesForDiscount: boolean = false;
364
+ build() {
365
+ Row() {
366
+ Text(`Total: ${this.total} `)
367
+ .fontSize(30)
368
+ Text(`Discount: ${this.qualifiesForDiscount} `)
369
+ .fontSize(30)
370
+ }
371
+ }
372
+ }
373
+ ```
@@ -0,0 +1,158 @@
1
+ 为了实现子组件向父组件要求更新@Param装饰变量的能力,开发者可以使用@Event装饰器。使用@Event装饰回调方法是一种规范,表明子组件需要传入更新数据源的回调。
2
+
3
+ @Event主要配合@Param实现数据的双向同步。在阅读本文档前,建议提前阅读:[@Param](../@Param:组件外部输入/arkts-new-param.md)。
4
+
5
+ 说明
6
+
7
+ 从API version 12开始,在@ComponentV2装饰的自定义组件中支持使用@Event装饰器。
8
+
9
+ 从API version 12开始,该装饰器支持在元服务中使用。
10
+
11
+ 从API version 23开始,该装饰器支持在ArkTS卡片中使用。
12
+
13
+ ## 概述
14
+
15
+ 由于@Param装饰的变量在本地无法更改,使用@Event装饰器装饰回调方法并调用,可以实现更新数据源的变量,再通过[@Local](../@Local装饰器:组件内部状态/arkts-new-local.md)的同步机制,将修改同步回@Param装饰的变量,以此达到主动更新@Param装饰变量的效果。
16
+
17
+ @Event用于装饰组件对外输出的方法:
18
+
19
+ * @Event装饰的回调方法中参数以及返回值由开发者决定。
20
+ * @Event装饰非回调类型的变量不会生效。当@Event没有初始化时,会自动生成一个空的函数作为默认回调。
21
+ * 当@Event未被外部初始化,但本地有默认值时,会使用本地默认的函数进行处理。
22
+
23
+ @Param标志着组件的输入,表明该变量受父组件影响,而@Event标志着组件的输出,可以通过该方法影响父组件。使用@Event装饰回调方法是一种规范,表明该回调作为自定义组件的输出。父组件需要判断是否提供对应方法用于子组件更改@Param变量的数据源。
24
+
25
+ ## 装饰器说明
26
+
27
+ | @Event属性装饰器 | 说明 |
28
+ | --- | --- |
29
+ | 装饰器参数 | 无。 |
30
+ | 允许装饰的变量类型 | 回调方法,例如()=>void、(x:number)=>boolean等。回调方法是否含有参数以及返回值由开发者决定。 |
31
+ | 允许传入的函数类型 | 箭头函数。 |
32
+
33
+ ## 限制条件
34
+
35
+ * @Event只能用在[@ComponentV2](../../../../学习UI范式基本语法/自定义组件/创建自定义组件/arkts-create-custom-components.md#componentv2)装饰的自定义组件中。当装饰非方法类型的变量时,不会有任何作用。
36
+
37
+ ```
38
+ 1. @ComponentV2
39
+ 2. struct Index {
40
+ 3. @Event changeFactory: () => void = () => {}; // 正确用法
41
+ 4. @Event message: string = 'abcd'; // 错误用法,装饰非函数类型变量,@Event无作用
42
+ 5. }
43
+ 6. @Component
44
+ 7. struct Index {
45
+ 8. @Event changeFactory: () => void = () => {}; // 错误用法,编译时报错
46
+ 9. }
47
+ ```
48
+
49
+ ## 使用场景
50
+
51
+ ### 更改父组件中变量
52
+
53
+ 使用@Event可以更改父组件中变量,当该变量作为子组件@Param变量的数据源时,该变化会同步回子组件的@Param变量。
54
+
55
+ ```
56
+ 1. @Entry
57
+ 2. @ComponentV2
58
+ 3. struct Index {
59
+ 4. @Local title: string = 'Title One';
60
+ 5. @Local fontColor: Color = Color.Red;
61
+
62
+ 7. build() {
63
+ 8. Column() {
64
+ 9. Child({
65
+ 10. title: this.title,
66
+ 11. fontColor: this.fontColor,
67
+ 12. changeFactory: (type: number) => {
68
+ 13. if (type == 1) {
69
+ 14. this.title = 'Title One';
70
+ 15. this.fontColor = Color.Red;
71
+ 16. } else if (type == 2) {
72
+ 17. this.title = 'Title Two';
73
+ 18. this.fontColor = Color.Green;
74
+ 19. }
75
+ 20. }
76
+ 21. })
77
+ 22. }
78
+ 23. }
79
+ 24. }
80
+
81
+ 26. @ComponentV2
82
+ 27. struct Child {
83
+ 28. @Param title: string = '';
84
+ 29. @Param fontColor: Color = Color.Black;
85
+ 30. @Event changeFactory: (x: number) => void = (x: number) => {};
86
+
87
+ 32. build() {
88
+ 33. Column() {
89
+ 34. Text(`${this.title}`)
90
+ 35. .fontColor(this.fontColor)
91
+ 36. // 使用changeFactory更改父组件中的变量type
92
+ 37. Button('change to Title Two')
93
+ 38. .onClick(() => {
94
+ 39. this.changeFactory(2);
95
+ 40. })
96
+ 41. Button('change to Title One')
97
+ 42. .onClick(() => {
98
+ 43. this.changeFactory(1);
99
+ 44. })
100
+ 45. }
101
+ 46. }
102
+ 47. }
103
+ ```
104
+
105
+ [EventDecoratorTest1.ets](https://gitcode.com/HarmonyOS_Samples/guide-snippets/blob/HarmonyOS-feature-20260402/ArkUISample/EventDecorator/entry/src/main/ets/pages/EventDecoratorTest1.ets#L15-L62)
106
+
107
+ 值得注意的是,使用@Event修改父组件的值是立刻生效的,但从父组件将变化同步回子组件的过程是异步的,即在调用完@Event的方法后,子组件内的值不会立刻变化。这是因为@Event将子组件值实际的变化能力交由父组件处理,在父组件实际决定如何处理后,将最终值在渲染之前同步回子组件。
108
+
109
+ ```
110
+ 1. import { hilog } from '@kit.PerformanceAnalysisKit';
111
+ 2. const TAG = '[Sample_EventDecorator]';
112
+ 3. const DOMAIN = 0xF811;
113
+ 4. @ComponentV2
114
+ 5. struct Child2 {
115
+ 6. @Param index: number = 0;
116
+ 7. @Event changeIndex: (val: number) => void;
117
+
118
+ 9. build() {
119
+ 10. Column() {
120
+ 11. Text(`Child index: ${this.index}`)
121
+ 12. .onClick(() => {
122
+ 13. this.changeIndex(20);
123
+ 14. // 输出子组件this.index,验证调用@Event后值不会立即同步回子组件
124
+ 15. hilog.info(DOMAIN, TAG, `after changeIndex ${this.index}`);
125
+ 16. })
126
+ 17. }
127
+ 18. }
128
+ 19. }
129
+ 20. @Entry
130
+ 21. @ComponentV2
131
+ 22. struct Index2 {
132
+ 23. @Local index: number = 0;
133
+
134
+ 25. build() {
135
+ 26. Column() {
136
+ 27. Child2({
137
+ 28. index: this.index,
138
+ 29. changeIndex: (val: number) => {
139
+ 30. this.index = val;
140
+ 31. // 输出父组件的index,用于对比子组件侧日志
141
+ 32. hilog.info(DOMAIN, TAG, `in changeIndex ${this.index}`);
142
+ 33. }
143
+ 34. })
144
+ 35. }
145
+ 36. }
146
+ 37. }
147
+ ```
148
+
149
+ [EventDecoratorTest2.ets](https://gitcode.com/HarmonyOS_Samples/guide-snippets/blob/HarmonyOS-feature-20260402/ArkUISample/EventDecorator/entry/src/main/ets/pages/EventDecoratorTest2.ets#L15-L51)
150
+
151
+ 在上面的示例中,点击文字触发@Event函数事件改变子组件的值,打印出的日志为:
152
+
153
+ ```
154
+ 1. in changeIndex 20
155
+ 2. after changeIndex 0
156
+ ```
157
+
158
+ 这表明在调用changeIndex之后,父组件中index的值已经变化,但子组件中的index值还没有同步变化。