create-vela-workflow 1.0.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.md +136 -0
- package/bin/cli.js +188 -0
- package/docs/ai-workflow-tutorial.md +462 -0
- package/docs/official-site-tutorial.md +391 -0
- package/package.json +34 -0
- package/templates/.github/HARNESS-ENGINEERING-GUIDE.md +407 -0
- package/templates/.github/agents/vela-knowledge.agent.md +45 -0
- package/templates/.github/agents/vela-s1-prd.agent.md +69 -0
- package/templates/.github/agents/vela-s2-tech.agent.md +66 -0
- package/templates/.github/agents/vela-s3-coding.agent.md +301 -0
- package/templates/.github/agents/vela-workflow.agent.md +110 -0
- package/templates/.github/copilot-instructions.md +64 -0
- package/templates/.github/prompts/vela-apis.prompt.md +98 -0
- package/templates/.github/prompts/vela-best-practices.prompt.md +93 -0
- package/templates/.github/prompts/vela-components.prompt.md +118 -0
- package/templates/.github/prompts/vela-dev-guide.prompt.md +622 -0
- package/templates/.github/rules/project-init.md +45 -0
- package/templates/.github/rules/vela-coding-convention.md +324 -0
- package/templates/.github/rules/vela-css.md +217 -0
- package/templates/.github/rules/vela-design-driven.md +306 -0
- package/templates/.github/rules/vela-figma-mcp.md +198 -0
- package/templates/.github/rules/vela-format.md +119 -0
- package/templates/.github/rules/vela-layout.md +67 -0
- package/templates/.github/rules/vela-platform.md +46 -0
- package/templates/.github/rules/vela-quality.md +109 -0
- package/templates/.kiro/hooks/figma-design-check.kiro.hook +14 -0
- package/templates/.kiro/hooks/post-coding-validation.kiro.hook +13 -0
- package/templates/.kiro/hooks/validate-ux-files.kiro.hook +16 -0
- package/templates/.kiro/settings/mcp.json +7 -0
- package/templates/.kiro/skills/vela-js-app/SKILL.md +1072 -0
- package/templates/.kiro/steering/workflow-conventions.md +110 -0
- package/templates/.workflow/resource-paths.json +62 -0
- package/templates/.workflow/scripts/.gitkeep +0 -0
- package/templates/.workflow/scripts/checkpoint_manager.js +284 -0
- package/templates/.workflow/scripts/context_loader.js +841 -0
- package/templates/.workflow/scripts/figma_export.js +346 -0
- package/templates/.workflow/scripts/session_manager.js +438 -0
- package/templates/.workflow/stages/.gitkeep +0 -0
- package/templates/.workflow/stages/commands.md +171 -0
- package/templates/.workflow/stages/s1_prd.md +286 -0
- package/templates/.workflow/stages/s2_tech_design.md +302 -0
- package/templates/.workflow/stages/s3_coding.md +699 -0
- package/templates/.workflow/stages/s4_simulator.md +259 -0
- package/templates/.workflow/workflow-config.json +46 -0
- package/templates/.workflow/workflow_starter.md +912 -0
|
@@ -0,0 +1,622 @@
|
|
|
1
|
+
# Vela 快应用完整开发指南
|
|
2
|
+
|
|
3
|
+
本文件是 Vela JS 应用开发的完整知识参考,涵盖框架概述、项目结构、配置、模板语法、样式系统、脚本、组件、接口和最佳实践。
|
|
4
|
+
|
|
5
|
+
官方文档站点:https://iot.mi.com/vela/quickapp/
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 框架概述
|
|
10
|
+
|
|
11
|
+
Xiaomi Vela JS 是小米基于 Vela OS 的轻量级 JS 应用框架,面向智能穿戴设备(手表)。采用前端 MVVM 开发范式,使用 `.ux` 文件编写页面,`manifest.json` 配置应用,Flexbox 布局,支持数据绑定和组件化开发。
|
|
12
|
+
|
|
13
|
+
## 创建项目
|
|
14
|
+
|
|
15
|
+
### 方式一:使用脚手架(推荐)
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm create aiot ux -- --name my-app --template vela-demo
|
|
19
|
+
cd my-app
|
|
20
|
+
npm install
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### 方式二:手动创建
|
|
24
|
+
|
|
25
|
+
参考下方项目结构手动创建。
|
|
26
|
+
|
|
27
|
+
## 项目结构
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
├── README.md
|
|
31
|
+
├── .gitignore
|
|
32
|
+
├── package.json
|
|
33
|
+
└── src/
|
|
34
|
+
├── manifest.json
|
|
35
|
+
├── app.ux
|
|
36
|
+
├── config-watch.json # 内容为 {}
|
|
37
|
+
├── pages/
|
|
38
|
+
│ ├── index/
|
|
39
|
+
│ │ └── index.ux
|
|
40
|
+
│ └── detail/
|
|
41
|
+
│ └── detail.ux
|
|
42
|
+
├── i18n/
|
|
43
|
+
│ ├── defaults.json
|
|
44
|
+
│ ├── zh-CN.json
|
|
45
|
+
│ └── en.json
|
|
46
|
+
└── common/
|
|
47
|
+
└── logo.png
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
注意:`manifest.json` 中 `router.pages` 的 key 需带 `pages/` 前缀(如 `"pages/index"` 对应 `src/pages/index/`)。
|
|
51
|
+
|
|
52
|
+
### package.json 示例
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"name": "my-app",
|
|
57
|
+
"version": "1.0.0",
|
|
58
|
+
"scripts": {
|
|
59
|
+
"start": "aiot start --watch",
|
|
60
|
+
"build": "aiot build",
|
|
61
|
+
"release": "aiot release"
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"aiot-toolkit": "^2.0.5"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### .gitignore
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
/node_modules
|
|
73
|
+
/dist
|
|
74
|
+
/build
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## manifest.json 配置
|
|
78
|
+
|
|
79
|
+
```json
|
|
80
|
+
{
|
|
81
|
+
"package": "com.company.demo",
|
|
82
|
+
"name": "应用名称",
|
|
83
|
+
"icon": "/common/logo.png",
|
|
84
|
+
"versionName": "1.0",
|
|
85
|
+
"versionCode": 1,
|
|
86
|
+
"minPlatformVersion": 1200,
|
|
87
|
+
"deviceTypeList": ["watch"],
|
|
88
|
+
"features": [
|
|
89
|
+
{ "name": "system.router" },
|
|
90
|
+
{ "name": "system.configuration" }
|
|
91
|
+
],
|
|
92
|
+
"config": {
|
|
93
|
+
"logLevel": "log",
|
|
94
|
+
"designWidth": 480
|
|
95
|
+
},
|
|
96
|
+
"router": {
|
|
97
|
+
"entry": "pages/index",
|
|
98
|
+
"pages": {
|
|
99
|
+
"pages/index": {
|
|
100
|
+
"component": "index"
|
|
101
|
+
},
|
|
102
|
+
"pages/detail": {
|
|
103
|
+
"component": "detail"
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
关键字段:
|
|
111
|
+
- `package`:应用包名,格式 com.company.module
|
|
112
|
+
- `name`:应用名称,6个汉字以内
|
|
113
|
+
- `versionCode`:整数版本号,每次发布+1
|
|
114
|
+
- `features`:接口声明数组,使用接口前必须声明
|
|
115
|
+
- `config.designWidth`:设计基准宽度,默认480px
|
|
116
|
+
- `router.entry`:首页路径
|
|
117
|
+
- `router.pages`:页面路由配置
|
|
118
|
+
- `router.pages[].launchMode`:支持 "standard"(默认)和 "singleTask"
|
|
119
|
+
|
|
120
|
+
## UX 文件格式
|
|
121
|
+
|
|
122
|
+
```html
|
|
123
|
+
<template>
|
|
124
|
+
<!-- 只能有一个根节点 -->
|
|
125
|
+
<div class="page">
|
|
126
|
+
<text class="title">{{title}}</text>
|
|
127
|
+
<input type="button" value="点击" onclick="handleClick" />
|
|
128
|
+
</div>
|
|
129
|
+
</template>
|
|
130
|
+
|
|
131
|
+
<style>
|
|
132
|
+
.page {
|
|
133
|
+
flex-direction: column;
|
|
134
|
+
justify-content: center;
|
|
135
|
+
align-items: center;
|
|
136
|
+
}
|
|
137
|
+
.title {
|
|
138
|
+
font-size: 30px;
|
|
139
|
+
color: #333333;
|
|
140
|
+
}
|
|
141
|
+
</style>
|
|
142
|
+
|
|
143
|
+
<script>
|
|
144
|
+
import router from '@system.router'
|
|
145
|
+
|
|
146
|
+
export default {
|
|
147
|
+
private: {
|
|
148
|
+
title: '示例页面'
|
|
149
|
+
},
|
|
150
|
+
onInit() {
|
|
151
|
+
console.log('页面初始化')
|
|
152
|
+
},
|
|
153
|
+
handleClick() {
|
|
154
|
+
router.push({ uri: '/pages/detail' })
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
</script>
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Template 模板语法
|
|
161
|
+
|
|
162
|
+
### 数据绑定
|
|
163
|
+
```html
|
|
164
|
+
<text>{{message}}</text>
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### 条件渲染
|
|
168
|
+
```html
|
|
169
|
+
<text if="{{show}}">显示</text>
|
|
170
|
+
<text elif="{{other}}">其他</text>
|
|
171
|
+
<text else>默认</text>
|
|
172
|
+
|
|
173
|
+
<!-- show 指令:不从DOM移除,仅隐藏 -->
|
|
174
|
+
<text show="{{visible}}">内容</text>
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### 列表渲染
|
|
178
|
+
```html
|
|
179
|
+
<div for="{{list}}" tid="id">
|
|
180
|
+
<text>{{$idx}}: {{$item.name}}</text>
|
|
181
|
+
</div>
|
|
182
|
+
|
|
183
|
+
<!-- 自定义变量名 -->
|
|
184
|
+
<div for="(index, item) in list" tid="id">
|
|
185
|
+
<text>{{index}}: {{item.name}}</text>
|
|
186
|
+
</div>
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
- `tid` 指定数组元素唯一ID,用于优化渲染
|
|
190
|
+
- for 只能循环数组,不能循环对象
|
|
191
|
+
- `<block>` 标签可用于逻辑控制,不产生额外DOM节点
|
|
192
|
+
|
|
193
|
+
### 事件绑定
|
|
194
|
+
```html
|
|
195
|
+
<text onclick="handleClick">点击</text>
|
|
196
|
+
<text onclick="handleClick($idx, $item)">传参</text>
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Style 样式系统
|
|
200
|
+
|
|
201
|
+
### 布局
|
|
202
|
+
- CSS Flexbox 布局,默认 `flex-direction: row`
|
|
203
|
+
- 盒模型为 `border-box`
|
|
204
|
+
- div 为 Flex 容器,text/span 为文本容器
|
|
205
|
+
|
|
206
|
+
### 长度单位
|
|
207
|
+
- `px`:相对于 designWidth 的适配单位,自动按屏幕宽度缩放
|
|
208
|
+
- `%`:百分比
|
|
209
|
+
- `dp`:设备独立像素(API Level 3+)
|
|
210
|
+
|
|
211
|
+
### 选择器
|
|
212
|
+
- `.class` / `#id` / `tag` / 并列 `.a, .b`
|
|
213
|
+
- 优先级:inline > #id > .class > tag
|
|
214
|
+
- 暂不支持后代选择器
|
|
215
|
+
|
|
216
|
+
### 样式预编译
|
|
217
|
+
```html
|
|
218
|
+
<style lang="less">
|
|
219
|
+
@import './style.less';
|
|
220
|
+
</style>
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### 通用样式属性
|
|
224
|
+
width, height, min-width, min-height, max-width, max-height, padding, margin, border, border-radius, background-color, background-image, background-size, background-position, color, opacity, display(flex|none), visibility, position(relative|absolute), flex, flex-grow, flex-shrink, flex-direction, align-items, justify-content, box-shadow, left/top/right/bottom
|
|
225
|
+
|
|
226
|
+
## Script 脚本
|
|
227
|
+
|
|
228
|
+
### 页面数据对象
|
|
229
|
+
```javascript
|
|
230
|
+
export default {
|
|
231
|
+
public: {}, // 允许被外部传入数据覆盖
|
|
232
|
+
protected: {}, // 允许被应用内部页面传参覆盖
|
|
233
|
+
private: {}, // 不允许被覆盖
|
|
234
|
+
|
|
235
|
+
// 组件级数据
|
|
236
|
+
data: {},
|
|
237
|
+
|
|
238
|
+
// 计算属性
|
|
239
|
+
computed: {
|
|
240
|
+
fullName() {
|
|
241
|
+
return this.firstName + ' ' + this.lastName
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### 页面生命周期
|
|
248
|
+
- `onInit()`:数据准备好,可使用页面数据
|
|
249
|
+
- `onReady()`:模板编译完成,可获取DOM节点
|
|
250
|
+
- `onShow()`:页面显示
|
|
251
|
+
- `onHide()`:页面隐藏
|
|
252
|
+
- `onDestroy()`:页面销毁,应释放资源
|
|
253
|
+
- `onBackPress()`:返回按键,return true 阻止返回
|
|
254
|
+
- `onRefresh(query)`:singleTask模式页面重新打开
|
|
255
|
+
- `onConfigurationChanged(event)`:系统配置变化
|
|
256
|
+
|
|
257
|
+
### APP 生命周期(app.ux)
|
|
258
|
+
- `onCreate()` / `onShow()` / `onHide()` / `onDestroy()` / `onError(e)`
|
|
259
|
+
|
|
260
|
+
### 全局对象和方法
|
|
261
|
+
```javascript
|
|
262
|
+
this.$app.$def.data1 // 访问 app.ux 数据
|
|
263
|
+
this.$app.$def.method1() // 调用 app.ux 方法
|
|
264
|
+
this.$app.exit() // 退出应用
|
|
265
|
+
this.$page.name // 页面名
|
|
266
|
+
this.$valid // 页面有效性
|
|
267
|
+
this.$element('id') // DOM操作
|
|
268
|
+
this.$watch('prop', 'handler') // 数据监听
|
|
269
|
+
this.$nextTick(() => {}) // 下次DOM更新后回调
|
|
270
|
+
|
|
271
|
+
// 事件通信
|
|
272
|
+
this.$on('event', handler)
|
|
273
|
+
this.$off('event', handler)
|
|
274
|
+
this.$emit('event', data) // 触发当前组件事件
|
|
275
|
+
this.$dispatch('event', data) // 向上传递
|
|
276
|
+
this.$broadcast('event', data) // 向下传递
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## 自定义组件
|
|
280
|
+
|
|
281
|
+
### 定义组件(comp.ux)
|
|
282
|
+
```html
|
|
283
|
+
<template>
|
|
284
|
+
<div><text>{{say}}</text></div>
|
|
285
|
+
</template>
|
|
286
|
+
<script>
|
|
287
|
+
export default {
|
|
288
|
+
props: ['say'],
|
|
289
|
+
data: { localVal: '' },
|
|
290
|
+
onInit() {},
|
|
291
|
+
onReady() {},
|
|
292
|
+
onDestroy() {}
|
|
293
|
+
}
|
|
294
|
+
</script>
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### 引入组件
|
|
298
|
+
```html
|
|
299
|
+
<import name="my-comp" src="./comp"></import>
|
|
300
|
+
<template>
|
|
301
|
+
<div>
|
|
302
|
+
<my-comp say="{{message}}" prop-object="{{obj}}"></my-comp>
|
|
303
|
+
</div>
|
|
304
|
+
</template>
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### 父子通信
|
|
308
|
+
- 父→子:通过 props 传递数据
|
|
309
|
+
- 子→父:`this.$emit('eventName', data)` + 父组件 `onemit-evt="handler"`
|
|
310
|
+
- 向上传递:`this.$dispatch()` + 父组件 `this.$on()`
|
|
311
|
+
- 向下传递:`this.$broadcast()` + 子组件 `this.$on()`
|
|
312
|
+
|
|
313
|
+
## 页面切换
|
|
314
|
+
|
|
315
|
+
```javascript
|
|
316
|
+
import router from '@system.router'
|
|
317
|
+
|
|
318
|
+
router.push({ uri: '/pages/detail', params: { id: '1' } })
|
|
319
|
+
router.replace({ uri: '/pages/detail', params: { id: '1' } })
|
|
320
|
+
router.back()
|
|
321
|
+
router.clear()
|
|
322
|
+
router.getLength()
|
|
323
|
+
router.getState() // { index, name, path }
|
|
324
|
+
router.getPages() // [{ name, path }, ...]
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
接收参数:在目标页面的 `protected`(应用内)或 `public`(应用外)中声明同名属性。
|
|
328
|
+
|
|
329
|
+
## 组件速查
|
|
330
|
+
|
|
331
|
+
官方组件文档:https://iot.mi.com/vela/quickapp/zh/components/
|
|
332
|
+
|
|
333
|
+
### 容器组件
|
|
334
|
+
| 组件 | 说明 | 文档 |
|
|
335
|
+
|------|------|------|
|
|
336
|
+
| div | 基础 Flex 容器 | [链接](https://iot.mi.com/vela/quickapp/zh/components/container/div.html) |
|
|
337
|
+
| list + list-item | 高性能列表 | [链接](https://iot.mi.com/vela/quickapp/zh/components/container/list.html) |
|
|
338
|
+
| scroll | 滚动容器 | [链接](https://iot.mi.com/vela/quickapp/zh/components/container/scroll.html) |
|
|
339
|
+
| swiper | 滑块视图 | [链接](https://iot.mi.com/vela/quickapp/zh/components/container/swiper.html) |
|
|
340
|
+
| stack | 层叠容器 | [链接](https://iot.mi.com/vela/quickapp/zh/components/container/stack.html) |
|
|
341
|
+
|
|
342
|
+
### 基础组件
|
|
343
|
+
| 组件 | 说明 | 文档 |
|
|
344
|
+
|------|------|------|
|
|
345
|
+
| text | 文本 | [链接](https://iot.mi.com/vela/quickapp/zh/components/basic/text.html) |
|
|
346
|
+
| image | 图片 | [链接](https://iot.mi.com/vela/quickapp/zh/components/basic/image.html) |
|
|
347
|
+
| span | 行内文本(仅作 text 子组件) | [链接](https://iot.mi.com/vela/quickapp/zh/components/basic/span.html) |
|
|
348
|
+
| a | 链接 | [链接](https://iot.mi.com/vela/quickapp/zh/components/basic/a.html) |
|
|
349
|
+
| progress | 进度条 | [链接](https://iot.mi.com/vela/quickapp/zh/components/basic/progress.html) |
|
|
350
|
+
| marquee | 跑马灯 | [链接](https://iot.mi.com/vela/quickapp/zh/components/basic/marquee.html) |
|
|
351
|
+
| chart | 图表 | [链接](https://iot.mi.com/vela/quickapp/zh/components/basic/chart.html) |
|
|
352
|
+
| qrcode | 二维码 | [链接](https://iot.mi.com/vela/quickapp/zh/components/basic/qrcode.html) |
|
|
353
|
+
| barcode | 条形码 | [链接](https://iot.mi.com/vela/quickapp/zh/components/basic/barcode.html) |
|
|
354
|
+
| image-animator | 帧动画 | [链接](https://iot.mi.com/vela/quickapp/zh/components/basic/image-animator.html) |
|
|
355
|
+
|
|
356
|
+
### 表单组件
|
|
357
|
+
| 组件 | 说明 | 文档 |
|
|
358
|
+
|------|------|------|
|
|
359
|
+
| input | 输入/按钮/选择(type: button/checkbox/radio) | [链接](https://iot.mi.com/vela/quickapp/zh/components/form/input.html) |
|
|
360
|
+
| picker | 选择器(type: text/date/time/multi-text) | [链接](https://iot.mi.com/vela/quickapp/zh/components/form/picker.html) |
|
|
361
|
+
| slider | 滑块 | [链接](https://iot.mi.com/vela/quickapp/zh/components/form/slider.html) |
|
|
362
|
+
| switch | 开关 | [链接](https://iot.mi.com/vela/quickapp/zh/components/form/switch.html) |
|
|
363
|
+
|
|
364
|
+
### 通用事件
|
|
365
|
+
所有组件支持:touchstart, touchmove, touchend, click, longpress, swipe
|
|
366
|
+
|
|
367
|
+
### 通用方法
|
|
368
|
+
```javascript
|
|
369
|
+
this.$element('id').getBoundingClientRect({
|
|
370
|
+
success(data) { /* left, right, top, bottom, width, height */ }
|
|
371
|
+
})
|
|
372
|
+
this.$element('input1').focus({ focus: true })
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
## 接口速查
|
|
376
|
+
|
|
377
|
+
官方接口文档:https://iot.mi.com/vela/quickapp/zh/features/
|
|
378
|
+
|
|
379
|
+
### 高频接口
|
|
380
|
+
|
|
381
|
+
**fetch — 网络请求**
|
|
382
|
+
声明:`{ "name": "system.fetch" }`
|
|
383
|
+
```javascript
|
|
384
|
+
import fetch from '@system.fetch'
|
|
385
|
+
fetch.fetch({
|
|
386
|
+
url: 'https://api.example.com/data',
|
|
387
|
+
method: 'GET',
|
|
388
|
+
header: { 'Content-Type': 'application/json' },
|
|
389
|
+
data: JSON.stringify({ key: 'value' }),
|
|
390
|
+
responseType: 'json',
|
|
391
|
+
success(res) { /* res.data, res.code, res.headers */ },
|
|
392
|
+
fail(data, code) { console.log(code) }
|
|
393
|
+
})
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
**storage — 键值存储**
|
|
397
|
+
声明:`{ "name": "system.storage" }`
|
|
398
|
+
```javascript
|
|
399
|
+
import storage from '@system.storage'
|
|
400
|
+
storage.set({ key: 'token', value: 'xxx' })
|
|
401
|
+
storage.get({ key: 'token', success(data) { console.log(data) } })
|
|
402
|
+
storage.delete({ key: 'token' })
|
|
403
|
+
storage.clear()
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
**audio — 音频播放**
|
|
407
|
+
声明:`{ "name": "system.audio" }`
|
|
408
|
+
```javascript
|
|
409
|
+
import audio from '@system.audio'
|
|
410
|
+
audio.src = '/common/music.mp3'
|
|
411
|
+
audio.volume = 0.8
|
|
412
|
+
audio.play() / audio.pause() / audio.stop()
|
|
413
|
+
audio.getPlayState({ success(data) { /* state, currentTime, duration */ } })
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
**prompt — 弹窗提示**
|
|
417
|
+
声明:`{ "name": "system.prompt" }`
|
|
418
|
+
```javascript
|
|
419
|
+
import prompt from '@system.prompt'
|
|
420
|
+
prompt.showToast({ message: '操作成功', duration: 2000 })
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### 全部接口列表
|
|
424
|
+
|
|
425
|
+
| 接口 | 声明 | 用途 | 文档 |
|
|
426
|
+
|------|------|------|------|
|
|
427
|
+
| router | 无需声明 | 页面路由 | [链接](https://iot.mi.com/vela/quickapp/zh/features/basic/router.html) |
|
|
428
|
+
| app | system.app | 应用管理 | [链接](https://iot.mi.com/vela/quickapp/zh/features/basic/app.html) |
|
|
429
|
+
| configuration | system.configuration | 应用配置 | [链接](https://iot.mi.com/vela/quickapp/zh/features/basic/configuration.html) |
|
|
430
|
+
| device | system.device | 设备信息 | [链接](https://iot.mi.com/vela/quickapp/zh/features/basic/device.html) |
|
|
431
|
+
| fetch | system.fetch | 网络请求 | [链接](https://iot.mi.com/vela/quickapp/zh/features/network/fetch.html) |
|
|
432
|
+
| request | system.request | 下载管理 | [链接](https://iot.mi.com/vela/quickapp/zh/features/network/request.html) |
|
|
433
|
+
| interconnect | system.interconnect | 设备互联 | [链接](https://iot.mi.com/vela/quickapp/zh/features/network/interconnect.html) |
|
|
434
|
+
| storage | system.storage | 键值存储 | [链接](https://iot.mi.com/vela/quickapp/zh/features/data/storage.html) |
|
|
435
|
+
| file | system.file | 文件操作 | [链接](https://iot.mi.com/vela/quickapp/zh/features/data/file.html) |
|
|
436
|
+
| network | system.network | 网络状态 | [链接](https://iot.mi.com/vela/quickapp/zh/features/system/network.html) |
|
|
437
|
+
| vibrator | system.vibrator | 振动 | [链接](https://iot.mi.com/vela/quickapp/zh/features/system/vibrator.html) |
|
|
438
|
+
| brightness | system.brightness | 屏幕亮度 | [链接](https://iot.mi.com/vela/quickapp/zh/features/system/brightness.html) |
|
|
439
|
+
| volume | system.volume | 音量控制 | [链接](https://iot.mi.com/vela/quickapp/zh/features/system/volume.html) |
|
|
440
|
+
| battery | system.battery | 电池信息 | [链接](https://iot.mi.com/vela/quickapp/zh/features/system/battery.html) |
|
|
441
|
+
| geolocation | system.geolocation | 地理位置 | [链接](https://iot.mi.com/vela/quickapp/zh/features/system/geolocation.html) |
|
|
442
|
+
| sensor | system.sensor | 传感器 | [链接](https://iot.mi.com/vela/quickapp/zh/features/system/sensor.html) |
|
|
443
|
+
| record | system.record | 录音 | [链接](https://iot.mi.com/vela/quickapp/zh/features/system/record.html) |
|
|
444
|
+
| alarm | system.alarm | 闹钟 | [链接](https://iot.mi.com/vela/quickapp/zh/features/system/alarm.html) |
|
|
445
|
+
| event | system.event | 系统事件 | [链接](https://iot.mi.com/vela/quickapp/zh/features/system/event.html) |
|
|
446
|
+
| audio | system.audio | 音频播放 | [链接](https://iot.mi.com/vela/quickapp/zh/features/other/audio.html) |
|
|
447
|
+
| prompt | system.prompt | 弹窗提示 | [链接](https://iot.mi.com/vela/quickapp/zh/features/other/prompt.html) |
|
|
448
|
+
| crypto | system.crypto | 加密 | [链接](https://iot.mi.com/vela/quickapp/zh/features/security/crypto.html) |
|
|
449
|
+
|
|
450
|
+
### 通用错误码
|
|
451
|
+
- 200:系统通用错误
|
|
452
|
+
- 201:用户拒绝
|
|
453
|
+
- 202:参数错误
|
|
454
|
+
- 203:功能不支持
|
|
455
|
+
- 204:请求超时
|
|
456
|
+
- 300:I/O 错误
|
|
457
|
+
|
|
458
|
+
## 文件存储分区
|
|
459
|
+
|
|
460
|
+
| 分区 | URI | 读写 | 说明 |
|
|
461
|
+
|------|-----|------|------|
|
|
462
|
+
| 应用资源 | /path | 只读 | 应用内置资源 |
|
|
463
|
+
| Cache | internal://cache/path | 读写 | 缓存,可能被系统清理 |
|
|
464
|
+
| Files | internal://files/path | 读写 | 永久小文件 |
|
|
465
|
+
| Mass | internal://mass/path | 读写 | 大文件,不保证可用 |
|
|
466
|
+
| Temp | internal://tmp/path | 只读 | 临时文件,重启后失效 |
|
|
467
|
+
|
|
468
|
+
## 动画样式
|
|
469
|
+
|
|
470
|
+
### transform
|
|
471
|
+
```css
|
|
472
|
+
div { transform: translate(10px, 20px) rotate(45deg) scale(1.5); }
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
### animation + @keyframes
|
|
476
|
+
```css
|
|
477
|
+
.box { animation-name: fadeIn; animation-duration: 1s; }
|
|
478
|
+
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
### transition
|
|
482
|
+
```css
|
|
483
|
+
.box { transition-property: width; transition-duration: 0.3s; }
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
## Media Query 媒体查询
|
|
487
|
+
|
|
488
|
+
```css
|
|
489
|
+
@media (shape: circle) {
|
|
490
|
+
.box { border-radius: 50%; }
|
|
491
|
+
}
|
|
492
|
+
@media (device-type: watch) and (min-width: 200) {
|
|
493
|
+
.box { width: 100%; }
|
|
494
|
+
}
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
支持的媒体特性:
|
|
498
|
+
- `shape`:circle / rect / pill-shaped
|
|
499
|
+
- `device-type`:watch / band / smartspeaker
|
|
500
|
+
- `width` / `min-width` / `max-width`(dp单位,不带单位书写)
|
|
501
|
+
- `height` / `min-height` / `max-height`
|
|
502
|
+
|
|
503
|
+
常见设备 dp 参考:
|
|
504
|
+
- Xiaomi Watch S1 Pro/S5:480×480px, DPR=2, 宽=240dp
|
|
505
|
+
- Xiaomi Watch S3/S4/H1:466×466px, DPR=2, 宽=233dp
|
|
506
|
+
- REDMI Watch 5:432×514px, DPR=2, 宽=216dp
|
|
507
|
+
- 小米手环9:192×490px, DPR=2, 宽=96dp
|
|
508
|
+
|
|
509
|
+
## 国际化(i18n)
|
|
510
|
+
|
|
511
|
+
```html
|
|
512
|
+
<text>{{ $t('message.hello') }}</text>
|
|
513
|
+
<text>{{ $t('message.greeting', { name: '小明' }) }}</text>
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
```javascript
|
|
517
|
+
this.$t('message.hello')
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
文件:`src/i18n/zh-CN.json`, `src/i18n/defaults.json`
|
|
521
|
+
|
|
522
|
+
## 最佳实践
|
|
523
|
+
|
|
524
|
+
### 内存优化
|
|
525
|
+
- 非 UI 数据不放 ViewModel(放在 export default 外部)
|
|
526
|
+
- 数据原地修改,避免重新赋值整个数组/对象
|
|
527
|
+
- 使用 `static` 标记不变节点
|
|
528
|
+
- 页面销毁时清除定时器
|
|
529
|
+
- 读取的数据用完后置 null 释放
|
|
530
|
+
|
|
531
|
+
### 启动性能
|
|
532
|
+
- 避免 setTimeout 延迟跳转,用 async/await
|
|
533
|
+
- Logo 页避免 HTTP 请求
|
|
534
|
+
- 首页数据做本地缓存,先读缓存展示
|
|
535
|
+
- UI 先行,不等数据加载完才渲染
|
|
536
|
+
|
|
537
|
+
### 渲染性能
|
|
538
|
+
- list 超过 10 条使用分页渲染
|
|
539
|
+
- 减少 border-radius 与背景图同时使用
|
|
540
|
+
- 图片尺寸与组件尺寸保持一致
|
|
541
|
+
- 减少标签嵌套层级
|
|
542
|
+
|
|
543
|
+
### 圆形屏幕安全区域
|
|
544
|
+
- 上下安全边距:屏幕高度 10%
|
|
545
|
+
- 左右安全边距:屏幕宽度 7-8%
|
|
546
|
+
- 内容超出一屏用 `<scroll scroll-y="true">` 包裹
|
|
547
|
+
|
|
548
|
+
```css
|
|
549
|
+
@media (shape: circle) {
|
|
550
|
+
.container { padding: 50px 36px; }
|
|
551
|
+
}
|
|
552
|
+
@media (shape: rect) {
|
|
553
|
+
.container { padding: 20px 16px; }
|
|
554
|
+
}
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
### 异步接口 Promise 封装
|
|
558
|
+
```javascript
|
|
559
|
+
function promisify(fn) {
|
|
560
|
+
return (opts = {}) => new Promise((resolve, reject) => {
|
|
561
|
+
fn({ ...opts, success: resolve, fail: (data, code) => reject({ data, code }) })
|
|
562
|
+
})
|
|
563
|
+
}
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
## 完整页面示例
|
|
567
|
+
|
|
568
|
+
```html
|
|
569
|
+
<template>
|
|
570
|
+
<div class="page">
|
|
571
|
+
<text class="title">{{title}}</text>
|
|
572
|
+
<div class="list-wrap">
|
|
573
|
+
<div for="{{items}}" tid="id" class="item" onclick="onItemClick($item)">
|
|
574
|
+
<image src="{{$item.icon}}" class="icon" />
|
|
575
|
+
<text class="name">{{$item.name}}</text>
|
|
576
|
+
</div>
|
|
577
|
+
</div>
|
|
578
|
+
<div if="{{items.length === 0}}" class="empty">
|
|
579
|
+
<text>暂无数据</text>
|
|
580
|
+
</div>
|
|
581
|
+
</div>
|
|
582
|
+
</template>
|
|
583
|
+
|
|
584
|
+
<style>
|
|
585
|
+
.page { flex-direction: column; padding: 20px; }
|
|
586
|
+
.title { font-size: 36px; font-weight: bold; margin-bottom: 20px; }
|
|
587
|
+
.list-wrap { flex-direction: column; }
|
|
588
|
+
.item {
|
|
589
|
+
flex-direction: row; align-items: center;
|
|
590
|
+
padding: 15px 0; border-bottom: 1px solid #eeeeee;
|
|
591
|
+
}
|
|
592
|
+
.icon { width: 60px; height: 60px; margin-right: 15px; }
|
|
593
|
+
.name { font-size: 28px; color: #333333; }
|
|
594
|
+
.empty { justify-content: center; align-items: center; margin-top: 100px; }
|
|
595
|
+
</style>
|
|
596
|
+
|
|
597
|
+
<script>
|
|
598
|
+
import router from '@system.router'
|
|
599
|
+
import storage from '@system.storage'
|
|
600
|
+
|
|
601
|
+
export default {
|
|
602
|
+
private: {
|
|
603
|
+
title: '我的应用',
|
|
604
|
+
items: []
|
|
605
|
+
},
|
|
606
|
+
onInit() {
|
|
607
|
+
this.loadData()
|
|
608
|
+
},
|
|
609
|
+
loadData() {
|
|
610
|
+
storage.get({
|
|
611
|
+
key: 'items',
|
|
612
|
+
success: (data) => {
|
|
613
|
+
if (data) { this.items = JSON.parse(data) }
|
|
614
|
+
}
|
|
615
|
+
})
|
|
616
|
+
},
|
|
617
|
+
onItemClick(item) {
|
|
618
|
+
router.push({ uri: '/pages/detail', params: { id: item.id } })
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
</script>
|
|
622
|
+
```
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: 项目初始化规范 — 脚手架命令、检查清单、禁止行为
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 项目初始化规范(强制执行)
|
|
7
|
+
|
|
8
|
+
## 唯一允许的初始化命令
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npx create-aiot ux --name {项目名} --template vela-demo
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
> `--template vela-demo` 用于自动选择模板,避免交互式提示导致命令阻塞。
|
|
15
|
+
|
|
16
|
+
## 禁止行为清单
|
|
17
|
+
|
|
18
|
+
| 编号 | 禁止行为 | 原因 |
|
|
19
|
+
|------|----------|------|
|
|
20
|
+
| N1 | 手动创建 package.json | 脚手架自动生成 |
|
|
21
|
+
| N2 | 手动创建 src/manifest.json | 脚手架自动生成 |
|
|
22
|
+
| N3 | 手动创建 src/app.ux | 脚手架自动生成 |
|
|
23
|
+
| N4 | 手动创建 src/config-watch.json | 脚手架自动生成 |
|
|
24
|
+
| N5 | 手动创建 src/i18n/ 目录 | 脚手架自动生成 |
|
|
25
|
+
| N6 | 手动创建 src/common/logo.png | 脚手架自动生成 |
|
|
26
|
+
| N7 | 使用 hap-toolkit 命令 | 应使用 create-aiot |
|
|
27
|
+
| N8 | 修改脚手架生成的基础文件结构 | 保持兼容性 |
|
|
28
|
+
|
|
29
|
+
## 执行前检查清单
|
|
30
|
+
|
|
31
|
+
| 检查项 | 检查方法 | 通过条件 |
|
|
32
|
+
|--------|----------|----------|
|
|
33
|
+
| 项目名规范 | 正则 `/^[a-z][a-z0-9-]*$/` | 仅小写字母、数字、连字符 |
|
|
34
|
+
| 目标目录不存在 | `ls {目录}/{项目名}` | 返回"No such file" |
|
|
35
|
+
| npm 源可用 | `npm config get registry` | 有效 registry URL |
|
|
36
|
+
| npx 可用 | `which npx` | 返回路径 |
|
|
37
|
+
|
|
38
|
+
## 初始化后允许的操作
|
|
39
|
+
|
|
40
|
+
- ✅ 添加新页面(src/pages/xxx/index.ux)
|
|
41
|
+
- ✅ 修改页面代码逻辑
|
|
42
|
+
- ✅ 添加自定义组件
|
|
43
|
+
- ✅ 修改样式文件
|
|
44
|
+
- ✅ 补全 README.md
|
|
45
|
+
- ✅ 补全 .gitignore
|