deveco-harness 0.1.0
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.
- package/README.en.md +71 -0
- package/README.md +71 -0
- package/deveco-harness.example.jsonc +32 -0
- package/dist/index.js +758 -0
- package/package.json +48 -0
- package/prompts/build.txt +164 -0
- package/prompts/plan.txt +118 -0
- package/skills/arkts-error-fixes/README.md +151 -0
- package/skills/arkts-error-fixes/SKILL.md +150 -0
- package/skills/arkts-error-fixes/assets/AnyTypeError.ets +269 -0
- package/skills/arkts-error-fixes/assets/AppStorageError.ets +22 -0
- package/skills/arkts-error-fixes/assets/ArrowFunctionConversionError.ets +42 -0
- package/skills/arkts-error-fixes/assets/AvoidAreaTypeError.ets +43 -0
- package/skills/arkts-error-fixes/assets/BreakpointTypeError.ets +71 -0
- package/skills/arkts-error-fixes/assets/CatchClauseTypeError.ets +54 -0
- package/skills/arkts-error-fixes/assets/ColorConsistencyError.ets +88 -0
- package/skills/arkts-error-fixes/assets/ColorPropertyError.ets +39 -0
- package/skills/arkts-error-fixes/assets/ContextTypeError.ets +105 -0
- package/skills/arkts-error-fixes/assets/DecoratorStateError.ets +64 -0
- package/skills/arkts-error-fixes/assets/DisplayListenerTypeError.ets +129 -0
- package/skills/arkts-error-fixes/assets/DuplicateEntryError.ets +35 -0
- package/skills/arkts-error-fixes/assets/ESObjectTypeError.ets +137 -0
- package/skills/arkts-error-fixes/assets/FontColorPropertyError.ets +42 -0
- package/skills/arkts-error-fixes/assets/FunctionReturnTypeError.ets +41 -0
- package/skills/arkts-error-fixes/assets/IDataSourceError.ets +79 -0
- package/skills/arkts-error-fixes/assets/ImplementationNotAllowedError.ets +38 -0
- package/skills/arkts-error-fixes/assets/InterfaceMethodSignatureError.ets +43 -0
- package/skills/arkts-error-fixes/assets/NotificationError.ets +34 -0
- package/skills/arkts-error-fixes/assets/ObjectLiteralInterfaceError.ets +49 -0
- package/skills/arkts-error-fixes/assets/ObjectLiteralTypeError.ets +54 -0
- package/skills/arkts-error-fixes/assets/ObjectSpreadError.ets +29 -0
- package/skills/arkts-error-fixes/assets/PossiblyNullError.ets +32 -0
- package/skills/arkts-error-fixes/assets/ResourceConversionError.ets +159 -0
- package/skills/arkts-error-fixes/assets/StandaloneFunctionContext.ets +116 -0
- package/skills/arkts-error-fixes/assets/StandaloneFunctionError.ets +85 -0
- package/skills/arkts-error-fixes/assets/StorageLinkDefaultError.ets +41 -0
- package/skills/arkts-error-fixes/assets/TitleButtonRectTypeError.ets +86 -0
- package/skills/arkts-error-fixes/assets/UnusedVariableWarning.ets +102 -0
- package/skills/arkts-error-fixes/assets/UtilityTypeError.ets +176 -0
- package/skills/arkts-error-fixes/assets/WindowRectSizeError.ets +65 -0
- package/skills/arkts-error-fixes/assets/WindowTypeError.ets +37 -0
- package/skills/arkts-error-fixes/reference/any_type_errors.md +433 -0
- package/skills/arkts-error-fixes/reference/appstorage_errors.md +95 -0
- package/skills/arkts-error-fixes/reference/arrow_function_conversion_errors.md +163 -0
- package/skills/arkts-error-fixes/reference/avoid_area_type_errors.md +59 -0
- package/skills/arkts-error-fixes/reference/breakpoint_type_errors.md +122 -0
- package/skills/arkts-error-fixes/reference/catch_clause_type_errors.md +89 -0
- package/skills/arkts-error-fixes/reference/color_consistency_errors.md +209 -0
- package/skills/arkts-error-fixes/reference/color_property_errors.md +136 -0
- package/skills/arkts-error-fixes/reference/context_type_errors.md +260 -0
- package/skills/arkts-error-fixes/reference/decorator_state_errors.md +109 -0
- package/skills/arkts-error-fixes/reference/display_listener_type_errors.md +149 -0
- package/skills/arkts-error-fixes/reference/duplicate_entry_errors.md +193 -0
- package/skills/arkts-error-fixes/reference/esobject_type_errors.md +110 -0
- package/skills/arkts-error-fixes/reference/fontcolor_property_errors.md +104 -0
- package/skills/arkts-error-fixes/reference/function_return_type_errors.md +194 -0
- package/skills/arkts-error-fixes/reference/idata_source_errors.md +77 -0
- package/skills/arkts-error-fixes/reference/implementation_not_allowed_errors.md +191 -0
- package/skills/arkts-error-fixes/reference/interface_method_signature_errors.md +143 -0
- package/skills/arkts-error-fixes/reference/notification_errors.md +110 -0
- package/skills/arkts-error-fixes/reference/object_literal_interface_errors.md +156 -0
- package/skills/arkts-error-fixes/reference/object_literal_type_errors.md +110 -0
- package/skills/arkts-error-fixes/reference/object_spread_errors.md +105 -0
- package/skills/arkts-error-fixes/reference/possibly_null_errors.md +156 -0
- package/skills/arkts-error-fixes/reference/resource_conversion_errors.md +154 -0
- package/skills/arkts-error-fixes/reference/standalone_function_errors.md +68 -0
- package/skills/arkts-error-fixes/reference/storage_link_default_errors.md +124 -0
- package/skills/arkts-error-fixes/reference/title_button_rect_type_errors.md +167 -0
- package/skills/arkts-error-fixes/reference/unused_variable_warnings.md +295 -0
- package/skills/arkts-error-fixes/reference/utility_type_errors.md +290 -0
- package/skills/arkts-error-fixes/reference/window_rect_size_errors.md +70 -0
- package/skills/arkts-error-fixes/reference/window_type_errors.md +95 -0
- package/skills/arkts-grammar-standards/SKILL.md +71 -0
- package/skills/arkts-grammar-standards/references/basic-syntax.md +103 -0
- package/skills/arkts-grammar-standards/references/restrictions.md +100 -0
- package/skills/arkts-grammar-standards/references/topic-aliases.json +93 -0
- package/skills/arkts-grammar-standards/references/ts-diff.md +108 -0
- package/skills/arkts-runtime-fix/SKILL.md +152 -0
- package/skills/arkts-runtime-fix/SKILL_CN.md +123 -0
- package/skills/arkts-runtime-fix/evals/evals.json +17 -0
- package/skills/arkts-runtime-fix/scripts/collect-hilog.mjs +116 -0
- package/skills/arkts-runtime-fix/scripts/collect-hilog.ts +115 -0
- package/skills/arkts-runtime-fix/scripts/fetch-faultlog.mjs +117 -0
- package/skills/arkts-runtime-fix/scripts/fetch-faultlog.ts +116 -0
- package/skills/arkts-runtime-fix/scripts/jscrash-report.mjs +149 -0
- package/skills/arkts-runtime-fix/scripts/parse-jscrash-log.mjs +126 -0
- package/skills/arkts-runtime-fix/scripts/parse-jscrash-log.ts +126 -0
- package/skills/arkts-runtime-fix/scripts/probe-faultlogger.mjs +160 -0
- package/skills/arkts-runtime-fix/scripts/probe-faultlogger.ts +160 -0
- package/skills/arkts-runtime-fix/scripts/shared/hdc.mjs +107 -0
- package/skills/arkts-runtime-fix/scripts/shared/hdc.ts +58 -0
- package/skills/arkts-runtime-fix/scripts/shared/jscrash-faultlogger.mjs +143 -0
- package/skills/arkts-runtime-fix/scripts/shared/jscrash-faultlogger.ts +148 -0
- package/skills/arkts-runtime-fix/scripts/shared/jscrash-parse.mjs +389 -0
- package/skills/arkts-runtime-fix/scripts/shared/jscrash-parse.ts +409 -0
- package/skills/arkts-runtime-fix/scripts/shared/utils.mjs +27 -0
- package/skills/arkts-runtime-fix/scripts/shared/utils.ts +27 -0
- package/skills/arkui-knowledge/SKILL.md +90 -0
- package/skills/arkui-knowledge/references/api-guardrails.md +60 -0
- package/skills/arkui-knowledge/references/common-mistakes.md +119 -0
- package/skills/arkui-knowledge/references/component-cookbook.md +135 -0
- package/skills/arkui-knowledge/references/ui-quality-checklist.md +36 -0
- package/skills/deveco-create-project/SKILL.md +144 -0
- package/skills/deveco-create-project/application/AppScope/app.json5 +10 -0
- package/skills/deveco-create-project/application/AppScope/resources/base/element/string.json +8 -0
- package/skills/deveco-create-project/application/AppScope/resources/base/media/background.png +0 -0
- package/skills/deveco-create-project/application/AppScope/resources/base/media/foreground.png +0 -0
- package/skills/deveco-create-project/application/AppScope/resources/base/media/layered_image.json +7 -0
- package/skills/deveco-create-project/application/build-profile.json5 +42 -0
- package/skills/deveco-create-project/application/code-linter.json5 +32 -0
- package/skills/deveco-create-project/application/entry/build-profile.json5 +33 -0
- package/skills/deveco-create-project/application/entry/hvigorfile.ts +7 -0
- package/skills/deveco-create-project/application/entry/obfuscation-rules.txt +23 -0
- package/skills/deveco-create-project/application/entry/oh-package.json5 +10 -0
- package/skills/deveco-create-project/application/entry/src/main/ets/entryability/EntryAbility.ets +63 -0
- package/skills/deveco-create-project/application/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets +31 -0
- package/skills/deveco-create-project/application/entry/src/main/ets/pages/Index.ets +38 -0
- package/skills/deveco-create-project/application/entry/src/main/module.json5 +50 -0
- package/skills/deveco-create-project/application/entry/src/main/resources/base/element/color.json +8 -0
- package/skills/deveco-create-project/application/entry/src/main/resources/base/element/float.json +8 -0
- package/skills/deveco-create-project/application/entry/src/main/resources/base/element/string.json +16 -0
- package/skills/deveco-create-project/application/entry/src/main/resources/base/media/background.png +0 -0
- package/skills/deveco-create-project/application/entry/src/main/resources/base/media/foreground.png +0 -0
- package/skills/deveco-create-project/application/entry/src/main/resources/base/media/layered_image.json +7 -0
- package/skills/deveco-create-project/application/entry/src/main/resources/base/media/startIcon.png +0 -0
- package/skills/deveco-create-project/application/entry/src/main/resources/base/profile/backup_config.json +3 -0
- package/skills/deveco-create-project/application/entry/src/main/resources/base/profile/main_pages.json +5 -0
- package/skills/deveco-create-project/application/entry/src/main/resources/dark/element/color.json +8 -0
- package/skills/deveco-create-project/application/hvigor/hvigor-config.json5 +23 -0
- package/skills/deveco-create-project/application/hvigorfile.ts +7 -0
- package/skills/deveco-create-project/application/oh-package.json5 +10 -0
- package/skills/deveco-create-project/scripts/copy-template.mjs +216 -0
- package/skills/deveco-create-project/scripts/copy-template.ts +214 -0
- package/skills/deveco-create-project/scripts/detect-sdk.mjs +82 -0
- package/skills/deveco-create-project/scripts/detect-sdk.ts +95 -0
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
# Context 类型错误解决方案
|
|
2
|
+
|
|
3
|
+
## 问题描述
|
|
4
|
+
|
|
5
|
+
在 HarmonyOS ArkUI 开发中,使用 `this.getUIContext().getHostContext()` 获取的 Context 类型为 `Context | undefined`,直接传递给需要 `Context` 类型参数的函数会触发类型错误:
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
Argument of type 'Context | undefined' is not assignable to parameter of type 'Context'.
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 问题示例
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
// ❌ 错误:Context 可能为 undefined
|
|
15
|
+
const context = this.getUIContext().getHostContext();
|
|
16
|
+
await window.getLastWindow(context); // 类型错误
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## 推荐解决方案
|
|
20
|
+
|
|
21
|
+
### 方案 1: 添加 null 检查
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
// ✅ 推荐:添加 null 检查
|
|
25
|
+
const context = this.getUIContext().getHostContext();
|
|
26
|
+
if (context) {
|
|
27
|
+
await window.getLastWindow(context);
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 方案 2: 使用类型断言
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
// ✅ 可选:使用类型断言
|
|
35
|
+
const context = this.getUIContext().getHostContext() as common.UIAbilityContext;
|
|
36
|
+
await window.getLastWindow(context);
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 方案 3: 使用可选链和空值合并
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
// ✅ 可选:使用可选链
|
|
43
|
+
const context = this.getUIContext().getHostContext();
|
|
44
|
+
if (context) {
|
|
45
|
+
await window.getLastWindow(context);
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## 迁移步骤
|
|
50
|
+
|
|
51
|
+
### 1. 识别 Context 类型错误
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
// 查找代码中的 Context 使用
|
|
55
|
+
const context = this.getUIContext().getHostContext();
|
|
56
|
+
window.getLastWindow(context); // 类型错误
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 2. 添加 null 检查
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
const context = this.getUIContext().getHostContext();
|
|
63
|
+
if (context) {
|
|
64
|
+
window.getLastWindow(context); // 正确
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 3. 使用类型断言(可选)
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
const context = this.getUIContext().getHostContext() as common.UIAbilityContext;
|
|
72
|
+
window.getLastWindow(context); // 正确
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## 完整示例
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
import { window } from '@kit.ArkUI';
|
|
79
|
+
import { common } from '@kit.AbilityKit';
|
|
80
|
+
|
|
81
|
+
@Entry
|
|
82
|
+
@Component
|
|
83
|
+
struct ContextTypeExample {
|
|
84
|
+
@State windowWidth: number = 0;
|
|
85
|
+
@State windowHeight: number = 0;
|
|
86
|
+
|
|
87
|
+
async aboutToAppear() {
|
|
88
|
+
// ✅ 正确:添加 null 检查
|
|
89
|
+
const context = this.getUIContext().getHostContext();
|
|
90
|
+
if (context) {
|
|
91
|
+
await this.getWindowSize(context as common.UIAbilityContext);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private async getWindowSize(context: common.UIAbilityContext) {
|
|
96
|
+
try {
|
|
97
|
+
const win = await window.getLastWindow(context);
|
|
98
|
+
const properties = win.getWindowProperties();
|
|
99
|
+
this.windowWidth = properties.windowRect.width;
|
|
100
|
+
this.windowHeight = properties.windowRect.height;
|
|
101
|
+
} catch (err) {
|
|
102
|
+
console.error('获取窗口大小失败:', err);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
build() {
|
|
107
|
+
Column() {
|
|
108
|
+
Text(`窗口大小: ${this.windowWidth} x ${this.windowHeight}`)
|
|
109
|
+
.fontSize(16)
|
|
110
|
+
}
|
|
111
|
+
.width('100%')
|
|
112
|
+
.height('100%')
|
|
113
|
+
.padding(16)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
> [查看完整示例](../assets/ContextTypeError.ets)
|
|
119
|
+
|
|
120
|
+
## 使用场景
|
|
121
|
+
|
|
122
|
+
### 1. 窗口操作
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
async operateWindow() {
|
|
126
|
+
const context = this.getUIContext().getHostContext();
|
|
127
|
+
if (context) {
|
|
128
|
+
const win = await window.getLastWindow(context);
|
|
129
|
+
await win.resize(800, 600);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### 2. 媒体查询
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
setupMediaQuery() {
|
|
138
|
+
const context = this.getUIContext().getHostContext();
|
|
139
|
+
if (context) {
|
|
140
|
+
const mediaQuery = this.getUIContext().getMediaQuery();
|
|
141
|
+
const listener = mediaQuery.matchMediaSync('(min-width: 600vp)');
|
|
142
|
+
listener.on('change', (result) => {
|
|
143
|
+
console.info(`Matches: ${result.matches}`);
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### 3. 文件操作
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
async readFile() {
|
|
153
|
+
const context = this.getUIContext().getHostContext();
|
|
154
|
+
if (context) {
|
|
155
|
+
const filesDir = context.filesDir;
|
|
156
|
+
// 读取文件操作
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## 最佳实践
|
|
162
|
+
|
|
163
|
+
### 1. 始终添加 null 检查
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
const context = this.getUIContext().getHostContext();
|
|
167
|
+
if (!context) {
|
|
168
|
+
console.error('Context is undefined');
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
// 使用 context
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### 2. 使用类型断言明确类型
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
const context = this.getUIContext().getHostContext() as common.UIAbilityContext;
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### 3. 封装 Context 获取
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
private getSafeContext(): common.UIAbilityContext | null {
|
|
184
|
+
const context = this.getUIContext().getHostContext();
|
|
185
|
+
return context ? context as common.UIAbilityContext : null;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
async operateWindow() {
|
|
189
|
+
const context = this.getSafeContext();
|
|
190
|
+
if (context) {
|
|
191
|
+
const win = await window.getLastWindow(context);
|
|
192
|
+
// 操作窗口
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### 4. 处理异步操作
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
async asyncOperation() {
|
|
201
|
+
const context = this.getUIContext().getHostContext();
|
|
202
|
+
if (context) {
|
|
203
|
+
try {
|
|
204
|
+
const win = await window.getLastWindow(context);
|
|
205
|
+
// 异步操作
|
|
206
|
+
} catch (err) {
|
|
207
|
+
console.error('操作失败:', err);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## 注意事项
|
|
214
|
+
|
|
215
|
+
1. **类型定义**:`getHostContext()` 返回 `Context | undefined`,必须处理 undefined 情况
|
|
216
|
+
|
|
217
|
+
2. **null 检查**:建议使用 `if (context)` 检查,而不是直接使用
|
|
218
|
+
|
|
219
|
+
3. **类型断言**:使用 `as common.UIAbilityContext` 明确类型,但确保类型正确
|
|
220
|
+
|
|
221
|
+
4. **异常处理**:在异步操作中添加 try-catch 处理可能的异常
|
|
222
|
+
|
|
223
|
+
5. **封装复用**:可以将 Context 获取逻辑封装为工具函数
|
|
224
|
+
|
|
225
|
+
## 相关 API 参考
|
|
226
|
+
|
|
227
|
+
- [UIContext.getHostContext()](https://developer.harmonyos.com/cn/docs/documentation/reference/arkui-ts/ts-methods-uicontext)
|
|
228
|
+
- [Context](https://developer.harmonyos.com/cn/docs/documentation/reference/apis-js-apis-application-context)
|
|
229
|
+
- [window.getLastWindow()](https://developer.harmonyos.com/cn/docs/documentation/reference/apis-arkui-window-0000001774529169)
|
|
230
|
+
|
|
231
|
+
## 迁移检查清单
|
|
232
|
+
|
|
233
|
+
- [ ] 识别所有使用 `getHostContext()` 的地方
|
|
234
|
+
- [ ] 添加 null 检查处理 undefined 情况
|
|
235
|
+
- [ ] 使用类型断言明确 Context 类型
|
|
236
|
+
- [ ] 添加异常处理
|
|
237
|
+
- [ ] 测试功能是否正常
|
|
238
|
+
- [ ] 确认类型错误已解决
|
|
239
|
+
|
|
240
|
+
## 常见问题
|
|
241
|
+
|
|
242
|
+
### Q: 为什么 `getHostContext()` 可能返回 undefined?
|
|
243
|
+
|
|
244
|
+
A: 在某些情况下(如组件未完全初始化),Context 可能尚未准备好,因此返回 undefined。
|
|
245
|
+
|
|
246
|
+
### Q: 可以使用非空断言 `!` 吗?
|
|
247
|
+
|
|
248
|
+
A: 可以,但不推荐。使用 `!` 会跳过类型检查,可能导致运行时错误。建议使用 null 检查。
|
|
249
|
+
|
|
250
|
+
### Q: 什么时候应该使用类型断言?
|
|
251
|
+
|
|
252
|
+
A: 当你确定 Context 的具体类型(如 `UIAbilityContext`)时,可以使用类型断言提高代码可读性。
|
|
253
|
+
|
|
254
|
+
### Q: 如何在多个地方复用 Context?
|
|
255
|
+
|
|
256
|
+
A: 可以封装一个工具函数或在组件中定义一个私有方法来安全地获取 Context。
|
|
257
|
+
|
|
258
|
+
### Q: null 检查会影响性能吗?
|
|
259
|
+
|
|
260
|
+
A: 不会。null 检查是非常轻量级的操作,对性能影响可以忽略不计。
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# @State 装饰器错误
|
|
2
|
+
|
|
3
|
+
## 错误描述
|
|
4
|
+
|
|
5
|
+
在 ArkTS 中,`@State` 装饰器只能用于 `@Component` 修饰的 struct 中,不能用于普通 class。
|
|
6
|
+
|
|
7
|
+
## 错误示例
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
// ❌ AI 经常生成的错误代码
|
|
11
|
+
class FoldableStateManager {
|
|
12
|
+
@State currentBreakpoint: string = 'sm';
|
|
13
|
+
@State isFolded: boolean = true;
|
|
14
|
+
|
|
15
|
+
aboutToAppear() {
|
|
16
|
+
// ...
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**错误信息:**
|
|
22
|
+
```
|
|
23
|
+
The '@State' decorator can only be used with 'struct'.
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## 原因分析
|
|
27
|
+
|
|
28
|
+
`@State` 是 ArkUI 框架的状态管理装饰器,用于在组件内部管理状态。它只能与 `@Component` 一起使用,不能用于普通类。
|
|
29
|
+
|
|
30
|
+
## 解决方案
|
|
31
|
+
|
|
32
|
+
### 方案1:移除 @State 装饰器(推荐用于非组件类)
|
|
33
|
+
|
|
34
|
+
如果类不需要响应式状态管理,移除 `@State` 装饰器:
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
// ✅ 正确的代码
|
|
38
|
+
class FoldableStateManager {
|
|
39
|
+
currentBreakpoint: string = 'sm';
|
|
40
|
+
isFolded: boolean = true;
|
|
41
|
+
|
|
42
|
+
aboutToAppear() {
|
|
43
|
+
// ...
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 方案2:使用 @Component struct(推荐用于状态管理)
|
|
49
|
+
|
|
50
|
+
如果需要状态管理,将类改为 @Component struct:
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
// ✅ 正确的代码
|
|
54
|
+
@Component
|
|
55
|
+
struct FoldableStateManager {
|
|
56
|
+
@State currentBreakpoint: string = 'sm';
|
|
57
|
+
@State isFolded: boolean = true;
|
|
58
|
+
|
|
59
|
+
aboutToAppear() {
|
|
60
|
+
// ...
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
build() {
|
|
64
|
+
// UI 组件
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## 简单示例
|
|
70
|
+
|
|
71
|
+
### 用于工具类
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
// ✅ 用于工具类时移除 @State
|
|
75
|
+
class DisplayManager {
|
|
76
|
+
currentBreakpoint: string = 'sm';
|
|
77
|
+
|
|
78
|
+
updateBreakpoint(width: number): string {
|
|
79
|
+
if (width < 600) return 'sm';
|
|
80
|
+
if (width < 840) return 'md';
|
|
81
|
+
return 'lg';
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 用于 @Component struct
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
// ✅ 用于组件时保留 @State
|
|
90
|
+
@Component
|
|
91
|
+
struct AdaptiveLayout {
|
|
92
|
+
@State currentBreakpoint: string = 'sm';
|
|
93
|
+
|
|
94
|
+
build() {
|
|
95
|
+
Column() {
|
|
96
|
+
Text(`Current: ${this.currentBreakpoint}`)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## 详细代码示例
|
|
103
|
+
|
|
104
|
+
> [DecoratorStateError.ets](../assets/DecoratorStateError.ets) - 完整的 @State 装饰器错误示例和修复方案
|
|
105
|
+
|
|
106
|
+
## 相关文档
|
|
107
|
+
|
|
108
|
+
- [ArkTS 状态管理](./state_migration.md)
|
|
109
|
+
- [HarmonyOS 官方文档](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-state-management-overview)
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# Display Listener Type Errors
|
|
2
|
+
|
|
3
|
+
## Error: Display on/off method type error
|
|
4
|
+
|
|
5
|
+
### Error Message
|
|
6
|
+
```
|
|
7
|
+
Type 'void' is not assignable to type 'number'
|
|
8
|
+
Argument of type 'number' is not assignable to parameter of type 'Callback<Rect>'
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
### Cause
|
|
12
|
+
The `display.on()` and `display.off()` methods are module-level methods, not instance methods of the `Display` class. Attempting to call them on a `Display` object instance causes type errors.
|
|
13
|
+
|
|
14
|
+
### Solution
|
|
15
|
+
Use `display.on()` and `display.off()` at the module level for listening to display changes. Use `Display.on()` and `Display.off()` on Display instances for instance-specific events like `availableAreaChange`.
|
|
16
|
+
|
|
17
|
+
### Key Points
|
|
18
|
+
- `display.on('add'|'remove'|'change', callback)` - Module level methods
|
|
19
|
+
- `Display.on('availableAreaChange', callback)` - Instance level methods
|
|
20
|
+
- `Display.on('foldStatusChange', callback)` - Instance level methods
|
|
21
|
+
- `Display.on('captureStatusChange', callback)` - Instance level methods
|
|
22
|
+
|
|
23
|
+
### Module Level Listeners
|
|
24
|
+
```typescript
|
|
25
|
+
import { display } from '@kit.ArkUI';
|
|
26
|
+
|
|
27
|
+
// ✅ Correct: Module level listener
|
|
28
|
+
let listener: (data: number) => void = (data: number) => {
|
|
29
|
+
console.info(`Display changed, ID: ${data}`);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
display.on('change', listener);
|
|
33
|
+
|
|
34
|
+
// Unregister
|
|
35
|
+
display.off('change', listener);
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Instance Level Listeners
|
|
39
|
+
```typescript
|
|
40
|
+
import { display } from '@kit.ArkUI';
|
|
41
|
+
|
|
42
|
+
const displayClass = display.getDefaultDisplaySync();
|
|
43
|
+
|
|
44
|
+
// ✅ Correct: Instance level listener
|
|
45
|
+
let areaListener: (data: display.Rect) => void = (data: display.Rect) => {
|
|
46
|
+
console.info(`Available area changed: ${JSON.stringify(data)}`);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
displayClass.on('availableAreaChange', areaListener);
|
|
50
|
+
|
|
51
|
+
// Unregister
|
|
52
|
+
displayClass.off('availableAreaChange', areaListener);
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### ❌ Wrong Usage
|
|
56
|
+
```typescript
|
|
57
|
+
const displayClass = display.getDefaultDisplaySync();
|
|
58
|
+
|
|
59
|
+
// ❌ Wrong: Calling on() on Display instance
|
|
60
|
+
let listener = displayClass.on('change', () => {
|
|
61
|
+
console.info('Display changed');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// ❌ Wrong: Calling off() on Display instance
|
|
65
|
+
displayClass.off('change', listener);
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### ✅ Correct Usage
|
|
69
|
+
```typescript
|
|
70
|
+
// ✅ Correct: Module level for display changes
|
|
71
|
+
let changeListener: (data: number) => void = (data: number) => {
|
|
72
|
+
console.info(`Display changed, ID: ${data}`);
|
|
73
|
+
};
|
|
74
|
+
display.on('change', changeListener);
|
|
75
|
+
|
|
76
|
+
// ✅ Correct: Instance level for available area changes
|
|
77
|
+
const displayClass = display.getDefaultDisplaySync();
|
|
78
|
+
let areaListener: (data: display.Rect) => void = (data: display.Rect) => {
|
|
79
|
+
console.info(`Available area changed: ${JSON.stringify(data)}`);
|
|
80
|
+
};
|
|
81
|
+
displayClass.on('availableAreaChange', areaListener);
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Available Listener Types
|
|
85
|
+
|
|
86
|
+
#### Module Level (display module)
|
|
87
|
+
- `on('add', callback: Callback<number>)` - Display added
|
|
88
|
+
- `on('remove', callback: Callback<number>)` - Display removed
|
|
89
|
+
- `on('change', callback: Callback<number>)` - Display changed
|
|
90
|
+
|
|
91
|
+
#### Instance Level (Display object)
|
|
92
|
+
- `on('availableAreaChange', callback: Callback<Rect>)` - Available area changed
|
|
93
|
+
- `on('foldStatusChange', callback: Callback<FoldStatus>)` - Fold status changed
|
|
94
|
+
- `on('captureStatusChange', callback: Callback<boolean>)` - Capture status changed
|
|
95
|
+
|
|
96
|
+
### Best Practices
|
|
97
|
+
1. **Use module level** for display add/remove/change events
|
|
98
|
+
2. **Use instance level** for display-specific events
|
|
99
|
+
3. **Always unregister** listeners in aboutToDisappear()
|
|
100
|
+
4. **Store listener references** for proper cleanup
|
|
101
|
+
5. **Use explicit types** for listener callbacks
|
|
102
|
+
|
|
103
|
+
### Component Integration
|
|
104
|
+
```typescript
|
|
105
|
+
@Entry
|
|
106
|
+
@Component
|
|
107
|
+
struct DisplayListenerExample {
|
|
108
|
+
private changeListener?: (data: number) => void;
|
|
109
|
+
private areaListener?: (data: display.Rect) => void;
|
|
110
|
+
|
|
111
|
+
aboutToAppear() {
|
|
112
|
+
// Register module level listener
|
|
113
|
+
this.changeListener = (data: number) => {
|
|
114
|
+
console.info(`Display changed: ${data}`);
|
|
115
|
+
};
|
|
116
|
+
display.on('change', this.changeListener);
|
|
117
|
+
|
|
118
|
+
// Register instance level listener
|
|
119
|
+
const displayClass = display.getDefaultDisplaySync();
|
|
120
|
+
this.areaListener = (data: display.Rect) => {
|
|
121
|
+
console.info(`Area changed: ${JSON.stringify(data)}`);
|
|
122
|
+
};
|
|
123
|
+
displayClass.on('availableAreaChange', this.areaListener);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
aboutToDisappear() {
|
|
127
|
+
// Unregister listeners
|
|
128
|
+
if (this.changeListener) {
|
|
129
|
+
display.off('change', this.changeListener);
|
|
130
|
+
this.changeListener = undefined;
|
|
131
|
+
}
|
|
132
|
+
if (this.areaListener) {
|
|
133
|
+
const displayClass = display.getDefaultDisplaySync();
|
|
134
|
+
displayClass.off('availableAreaChange', this.areaListener);
|
|
135
|
+
this.areaListener = undefined;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
build() {
|
|
140
|
+
Column() {
|
|
141
|
+
Text('Display Listener Example')
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Related Files
|
|
148
|
+
- [Code Example](../assets/DisplayListenerTypeError.ets)
|
|
149
|
+
- [Display API Documentation](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-display)
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# 多个 @Entry 装饰器错误
|
|
2
|
+
|
|
3
|
+
## 问题描述
|
|
4
|
+
|
|
5
|
+
在 ArkTS 中,一个 `.ets` 文件只能有一个 `@Entry` 装饰器。如果在同一个文件中使用多个 `@Entry` 装饰器,会导致编译错误。
|
|
6
|
+
|
|
7
|
+
### 错误信息
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
Duplicate entry annotation
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
或
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
More than one @Entry decorator in the same file
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## 错误示例
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
// ❌ 错误:一个文件中有两个 @Entry
|
|
23
|
+
@Entry
|
|
24
|
+
@Component
|
|
25
|
+
struct FirstPage {
|
|
26
|
+
build() {
|
|
27
|
+
Column() {
|
|
28
|
+
Text('Page 1')
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@Entry
|
|
34
|
+
@Component
|
|
35
|
+
struct SecondPage {
|
|
36
|
+
build() {
|
|
37
|
+
Column() {
|
|
38
|
+
Text('Page 2')
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## 解决方案
|
|
45
|
+
|
|
46
|
+
### 方案一:将子组件改为普通 @Component(推荐)
|
|
47
|
+
|
|
48
|
+
将多余的 `@Entry` 改为普通 `@Component`,避免重复的入口声明。
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
// ✅ 正确:只有一个 @Entry,其他用 @Component
|
|
52
|
+
@Entry
|
|
53
|
+
@Component
|
|
54
|
+
struct MainPage {
|
|
55
|
+
build() {
|
|
56
|
+
Column() {
|
|
57
|
+
Text('Main Page')
|
|
58
|
+
ChildComponent()
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@Component
|
|
64
|
+
struct ChildComponent {
|
|
65
|
+
build() {
|
|
66
|
+
Text('Child Component')
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 方案二:拆分到不同文件
|
|
72
|
+
|
|
73
|
+
将每个页面组件拆分到独立的文件中。
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
// mainPage.ets
|
|
77
|
+
@Entry
|
|
78
|
+
@Component
|
|
79
|
+
struct MainPage {
|
|
80
|
+
build() {
|
|
81
|
+
Column() {
|
|
82
|
+
Text('Main Page')
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
// subPage.ets - 单独的文件
|
|
90
|
+
@Entry
|
|
91
|
+
@Component
|
|
92
|
+
struct SubPage {
|
|
93
|
+
build() {
|
|
94
|
+
Column() {
|
|
95
|
+
Text('Sub Page')
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### 方案三:使用状态管理实现多页面
|
|
102
|
+
|
|
103
|
+
如果需要在多个视图之间切换,可以使用 `@State` 和条件渲染:
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
@Entry
|
|
107
|
+
@Component
|
|
108
|
+
struct MultiViewPage {
|
|
109
|
+
@State currentView: number = 0;
|
|
110
|
+
|
|
111
|
+
build() {
|
|
112
|
+
Column() {
|
|
113
|
+
if (this.currentView === 0) {
|
|
114
|
+
ViewOne()
|
|
115
|
+
} else {
|
|
116
|
+
ViewTwo()
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
Row() {
|
|
120
|
+
Button('View 1')
|
|
121
|
+
.onClick(() => this.currentView = 0)
|
|
122
|
+
Button('View 2')
|
|
123
|
+
.onClick(() => this.currentView = 1)
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
@Component
|
|
130
|
+
struct ViewOne {
|
|
131
|
+
build() {
|
|
132
|
+
Text('View 1').fontSize(24)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
@Component
|
|
137
|
+
struct ViewTwo {
|
|
138
|
+
build() {
|
|
139
|
+
Text('View 2').fontSize(24)
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## 简单示例
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
@Entry
|
|
148
|
+
@Component
|
|
149
|
+
struct PageExample {
|
|
150
|
+
@State message: string = 'Hello';
|
|
151
|
+
|
|
152
|
+
build() {
|
|
153
|
+
Column() {
|
|
154
|
+
Text(this.message)
|
|
155
|
+
.fontSize(24)
|
|
156
|
+
|
|
157
|
+
// 使用 @Component 装饰的子组件
|
|
158
|
+
ContentSection()
|
|
159
|
+
}
|
|
160
|
+
.width('100%')
|
|
161
|
+
.height('100%')
|
|
162
|
+
.padding(20)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
@Component
|
|
167
|
+
struct ContentSection {
|
|
168
|
+
@State count: number = 0;
|
|
169
|
+
|
|
170
|
+
build() {
|
|
171
|
+
Column() {
|
|
172
|
+
Text(`Count: ${this.count}`)
|
|
173
|
+
.fontSize(18)
|
|
174
|
+
|
|
175
|
+
Button('Add')
|
|
176
|
+
.onClick(() => {
|
|
177
|
+
this.count++;
|
|
178
|
+
})
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## 详细代码示例
|
|
185
|
+
|
|
186
|
+
- [DuplicateEntryError.ets](../assets/DuplicateEntryError.ets) - 完整的多个 @Entry 错误修复示例
|
|
187
|
+
|
|
188
|
+
## 最佳实践
|
|
189
|
+
|
|
190
|
+
1. **每个文件一个 @Entry**:保持每个 `.ets` 文件只有一个入口组件
|
|
191
|
+
2. **使用 @Component 复用 UI**:使用 `@Component` 装饰器创建可复用的 UI 组件
|
|
192
|
+
3. **合理拆分文件**:将不同页面拆分到独立文件,便于管理和维护
|
|
193
|
+
4. **状态提升**:如果多个组件需要共享状态,将状态提升到共同的父组件中
|