@microi.net/cli 5.9.1 → 5.9.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.
- package/.codebuddy-plugin/marketplace.json +2 -2
- package/.codebuddy-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.workbuddy-plugin/marketplace.json +2 -2
- package/.workbuddy-plugin/plugin.json +1 -1
- package/LICENSE +21 -21
- package/README.md +71 -71
- package/assets/build-meta.json +5 -5
- package/assets/feature-matrix.json +138 -138
- package/assets/logo.svg +4 -4
- package/cordis.patch.yml +1 -1
- package/package.json +1 -1
- package/scripts/microi-codex-broker.js +466 -450
- package/scripts/microi-codex-router.js +634 -618
- package/scripts/microi-skills.meta.json +386 -377
- package/skills/.microi-skills-version.json +2 -2
- package/skills/.progressive-disclosure-manifest.json +148 -123
- package/skills/README.md +287 -287
- package/skills/ai-engine/SKILL.md +269 -269
- package/skills/ai-engine/agents/openai.yaml +4 -4
- package/skills/ai-engine/references/ai-employees.md +48 -48
- package/skills/ai-engine/references/self-hosted-digital-human.md +59 -59
- package/skills/ai-platform-governance/SKILL.md +177 -177
- package/skills/ai-platform-governance/references/progressive-01-/345/212/237/350/203/275/345/274/200/345/205/263.md +190 -190
- package/skills/app-store/SKILL.md +525 -525
- package/skills/app-store/agents/openai.yaml +4 -4
- package/skills/business-blueprint/SKILL.md +193 -193
- package/skills/datasource-engine/SKILL.md +93 -93
- package/skills/datasource-engine/agents/openai.yaml +4 -4
- package/skills/dos-orm/SKILL.md +101 -95
- package/skills/dos-orm/references/api-reference.md +229 -229
- package/skills/email-engine/SKILL.md +81 -81
- package/skills/email-engine/references/v8-email.md +34 -34
- package/skills/job-engine/SKILL.md +176 -176
- package/skills/job-engine/agents/openai.yaml +4 -4
- package/skills/message-notification/SKILL.md +156 -156
- package/skills/message-notification/agents/openai.yaml +5 -5
- package/skills/message-notification/references/contracts.md +102 -102
- package/skills/microi/SKILL.md +14 -14
- package/skills/microi-ai-app-auth.js +652 -652
- package/skills/microi-ai-application/SKILL.md +115 -115
- package/skills/microi-ai-application/agents/openai.yaml +4 -4
- package/skills/microi-ai-application/references/frontend-baseline.md +164 -164
- package/skills/microi-client-frontend/SKILL.md +242 -242
- package/skills/microi-client-frontend/references/progressive-01-3-/345/212/250/346/200/201/346/214/211/351/222/256/347/263/273/347/273/237.md +144 -144
- package/skills/microi-client-frontend/references/progressive-02-8-/350/277/220/350/241/214/346/227/266/351/253/230/351/242/221/345/235/221/345/244/215/347/233/230.md +196 -196
- package/skills/microi-client-frontend/references/progressive-03-vue3-/345/211/215/347/253/257/345/276/256/346/234/215/345/212/241/345/256/277/344/270/273/350/247/204/345/210/231.md +167 -167
- package/skills/microi-codex-installer/SKILL.md +231 -231
- package/skills/microi-codex-installer/agents/openai.yaml +7 -7
- package/skills/microi-datasource-mapping/SKILL.md +122 -122
- package/skills/microi-db-schema/SKILL.md +175 -175
- package/skills/microi-db-schema/agents/openai.yaml +4 -4
- package/skills/microi-db-schema/references/core-tables.md +695 -695
- package/skills/microi-db-schema/references/form-component-options.md +256 -256
- package/skills/microi-db-schema/references/schema-overview.md +202 -202
- package/skills/microi-db-schema/references/schema.md +646 -646
- package/skills/microi-db-schema/references/table-catalog.md +1599 -1599
- package/skills/microi-deployment/SKILL.md +239 -220
- package/skills/microi-deployment/references/deployment-matrix.md +109 -109
- package/skills/microi-docs-coverage/SKILL.md +133 -133
- package/skills/microi-docs-coverage/references/capability-map.md +90 -90
- package/skills/microi-docs-coverage/scripts/audit-doc-skill-coverage.mjs +894 -894
- package/skills/microi-form-engine/SKILL.md +338 -333
- package/skills/microi-form-engine/references/component-catalog.md +218 -218
- package/skills/microi-form-engine/references/data-source-events.md +124 -124
- package/skills/microi-frontend-sdk/SKILL.md +194 -194
- package/skills/microi-frontend-sdk/references/progressive-01-token-/345/275/223/345/211/215/347/231/273/345/275/225/347/224/250/346/210/267/344/270/216/345/275/223/345/211/215/347/273/210/347/253/257/347/231/273/345/275/225/345/215/217/350/256/256.md +176 -176
- package/skills/microi-left-right-layout/SKILL.md +141 -141
- package/skills/microi-microservice/SKILL.md +330 -328
- package/skills/microi-microservice/references/runtime-delivery.md +278 -278
- package/skills/microi-mobile-app-quality/SKILL.md +203 -197
- package/skills/microi-mobile-app-quality/references/mobile-first-delivery.md +75 -0
- package/skills/microi-mobile-app-quality/references/progressive-01-4-/351/207/215/350/246/201/346/214/211/351/222/256/345/277/205/351/241/273/345/270/246/345/233/276/346/240/207.md +227 -224
- package/skills/microi-mobile-app-quality/references/progressive-02-9-/344/270/273/351/242/230/345/210/207/346/215/242/345/277/205/351/241/273/347/234/237/345/256/236/344/270/224/345/205/250/345/261/200/347/224/237/346/225/210.md +129 -128
- package/skills/microi-solution-quotation/SKILL.md +78 -78
- package/skills/microi-solution-quotation/agents/openai.yaml +4 -4
- package/skills/microi-solution-quotation/scripts/build_solution_quote.py +296 -296
- package/skills/microi-sso/SKILL.md +95 -91
- package/skills/microi-sso/references/acceptance.md +51 -49
- package/skills/microi-sso/references/configuration-and-security.md +53 -53
- package/skills/microi-sso/references/inbound.md +53 -53
- package/skills/microi-sso/references/outbound.md +43 -39
- package/skills/microi-ui/SKILL.md +192 -192
- package/skills/microi-ui/references/progressive-01-/347/247/273/345/212/250/347/253/257/345/234/272/346/231/257/350/223/235/345/233/276.md +183 -183
- package/skills/microi-uniapp-frontend/SKILL.md +206 -199
- package/skills/microi-uniapp-frontend/references/progressive-01-/347/247/273/345/212/250/347/253/257/345/210/206/347/261/273-/345/217/214/346/240/217/345/210/227/350/241/250/347/213/254/347/253/213/346/273/232/345/212/250.md +261 -261
- package/skills/microi-uniapp-frontend/references/progressive-02-/345/205/263/351/224/256/344/270/232/345/212/241/350/265/204/344/272/247/344/270/215/345/276/227/351/273/230/350/256/244/351/200/211/344/270/255.md +154 -154
- package/skills/microi.v8.js +1921 -1921
- package/skills/module-engine/SKILL.md +255 -255
- package/skills/module-engine/references/module-config.md +204 -204
- package/skills/ocr-engine/SKILL.md +113 -113
- package/skills/ocr-engine/agents/openai.yaml +4 -4
- package/skills/page-engine/SKILL.md +206 -206
- package/skills/page-engine/examples/compact-dashboard.json +1444 -1444
- package/skills/page-engine/references/progressive-01-/346/211/200/346/234/211/347/273/204/344/273/266/347/261/273/345/236/213.md +234 -234
- package/skills/page-engine/references/progressive-02-/347/211/210/346/234/254/345/216/206/345/217/262-/345/271/266/345/217/221/344/277/235/345/255/230/344/270/216/345/233/236/346/273/232.md +60 -60
- package/skills/performance-testing/SKILL.md +227 -221
- package/skills/playwright-e2e/SKILL.md +197 -196
- package/skills/playwright-e2e/references/progressive-01-/345/205/250/350/207/252/345/212/250/347/231/273/345/275/225-/345/205/215/351/252/214/350/257/201/347/240/201-/344/275/206/344/270/215/345/205/215/345/257/206/347/240/201-/345/277/205/350/257/273.md +173 -173
- package/skills/playwright-e2e/references/progressive-02-/346/226/207/345/255/227/345/257/271/346/257/224/345/272/246/344/270/216/345/217/257/350/257/273/346/200/247/350/207/252/345/212/250/345/214/226/346/243/200/346/237/245-/345/277/205/345/201/232.md +183 -183
- package/skills/playwright-e2e/references/progressive-03-microi-helper-/346/250/241/346/235/277.md +221 -221
- package/skills/playwright-e2e/references/progressive-04-ci-/345/273/272/350/256/256.md +115 -115
- package/skills/print-engine/SKILL.md +259 -259
- package/skills/production-readonly-audit/SKILL.md +41 -41
- package/skills/report-engine/SKILL.md +71 -71
- package/skills/report-engine/agents/openai.yaml +4 -4
- package/skills/scripts/optimize-progressive-disclosure.mjs +204 -204
- package/skills/scripts/refresh-progressive-disclosure.mjs +64 -64
- package/skills/scripts/sync-embedded-skills.mjs +46 -46
- package/skills/scripts/validate-progressive-disclosure.mjs +57 -57
- package/skills/search-engine/SKILL.md +75 -75
- package/skills/search-engine/agents/openai.yaml +4 -4
- package/skills/spider-engine/SKILL.md +190 -190
- package/skills/system-observability/SKILL.md +259 -246
- package/skills/system-observability/references/memory-incident-triage.md +77 -77
- package/skills/translate-engine/SKILL.md +140 -140
- package/skills/translate-engine/agents/openai.yaml +4 -4
- package/skills/ui-design/SKILL.md +223 -223
- package/skills/ui-design/assets/pattern-showcase/app.js +54 -54
- package/skills/ui-design/assets/pattern-showcase/index.html +163 -163
- package/skills/ui-design/assets/pattern-showcase/styles.css +311 -311
- package/skills/ui-design/assets/templates/MCI-DESIGN.md +206 -206
- package/skills/ui-design/references/design-pattern-library.md +184 -184
- package/skills/ui-design/references/mci-design-contract.md +163 -163
- package/skills/ui-design/references/motion-and-media.md +78 -78
- package/skills/ui-design/references/product-flow-recipes.md +94 -94
- package/skills/ui-design/references/progressive-01-/351/242/234/350/211/262/344/275/223/347/263/273-css-variables-/346/224/257/346/214/201/344/270/273/351/242/230/345/210/207/346/215/242.md +218 -218
- package/skills/ui-design/references/progressive-02-/345/255/227/344/275/223.md +164 -164
- package/skills/ui-design/references/progressive-03-/345/212/250/346/225/210/350/247/204/350/214/203-/344/270/260/345/257/214/344/275/206/344/270/215/345/215/241.md +235 -235
- package/skills/ui-design/references/progressive-04-/347/273/204/344/273/266/351/243/216/346/240/274/351/200/237/346/237/245.md +152 -152
- package/skills/ui-design/references/progressive-05-/347/247/273/345/212/250/347/253/257/344/270/223/347/224/250/350/247/204/350/214/203.md +238 -238
- package/skills/ui-design/references/progressive-06-/344/270/273/351/242/230/345/210/207/346/215/242/345/256/236/347/216/260.md +194 -194
- package/skills/ui-design/references/progressive-07-/351/200/237/346/237/245-/344/273/216/345/244/264/346/220/255/345/273/272/344/270/200/344/270/252/347/247/273/345/212/250/347/253/257/351/241/265/351/235/242.md +207 -207
- package/skills/ui-design/references/progressive-08-/350/241/250/345/215/225/345/210/206/347/273/204/350/247/204/350/214/203-tabs-vs-collapsegroup-/345/274/272/345/210/266.md +142 -142
- package/skills/uniapp-mall-assets/SKILL.md +176 -176
- package/skills/unity-integration/SKILL.md +178 -171
- package/skills/unity-integration/agents/openai.yaml +4 -4
- package/skills/unity-integration/references/ai-app-delivery.md +119 -119
- package/skills/unity-integration/references/sdk-api.md +82 -82
- package/skills/unity-integration/references/toolbox-migration.md +66 -66
- package/skills/unity-integration/references/webgl-hosting.md +57 -57
- package/skills/v8-api-config/SKILL.md +388 -388
- package/skills/v8-cache-pattern/SKILL.md +312 -312
- package/skills/v8-crud-api/SKILL.md +179 -178
- package/skills/v8-crud-api/references/progressive-01-/346/237/245/350/257/242/345/210/227/350/241/250-/345/210/206/351/241/265.md +226 -226
- package/skills/v8-crud-api/references/progressive-02-where-/346/235/241/344/273/266/350/257/255/346/263/225/351/200/237/346/237/245.md +49 -49
- package/skills/v8-debugging/SKILL.md +284 -284
- package/skills/v8-explorer-tree/SKILL.md +228 -228
- package/skills/v8-export-import/SKILL.md +219 -219
- package/skills/v8-export-import/references/progressive-01-excellayout-/351/253/230/347/272/247/350/207/252/347/224/261/345/270/203/345/261/200.md +211 -211
- package/skills/v8-export-import/references/progressive-02-powerpoint-/345/257/274/345/207/272.md +202 -202
- package/skills/v8-export-import/references/progressive-03-/345/256/211/345/205/250-/346/200/247/350/203/275/346/263/250/346/204/217.md +42 -42
- package/skills/v8-file-upload/SKILL.md +255 -284
- package/skills/v8-file-upload/references/cdn-alias-repair.md +13 -0
- package/skills/v8-file-upload/references/progressive-01-/345/205/254/346/234/211/346/241/266-vs-/347/247/201/346/234/211/346/241/266.md +263 -263
- package/skills/v8-file-upload/references/progressive-02-office-/346/226/207/344/273/266/345/234/250/347/272/277/347/274/226/350/276/221/347/211/210/346/234/254/345/217/267/350/247/204/345/210/231.md +161 -161
- package/skills/v8-file-upload/references/progressive-03-/347/251/272/347/233/256/345/275/225/346/240/207/350/256/260/344/270/216/350/277/234/347/250/213/344/270/213/350/275/275.md +36 -0
- package/skills/v8-formengine-http/SKILL.md +238 -238
- package/skills/v8-frontend-events/SKILL.md +180 -180
- package/skills/v8-frontend-events/references/bluetooth-print-api.md +135 -135
- package/skills/v8-frontend-events/references/bluetooth-print.md +258 -258
- package/skills/v8-frontend-events/references/progressive-01-/345/210/227/350/241/250/344/272/213/344/273/266.md +219 -219
- package/skills/v8-http-integration/SKILL.md +182 -182
- package/skills/v8-http-integration/references/progressive-01-get-/350/257/267/346/261/202.md +220 -220
- package/skills/v8-http-integration/references/progressive-02-/351/224/231/350/257/257/345/244/204/347/220/206/346/250/241/345/274/217.md +44 -44
- package/skills/v8-image-processing/SKILL.md +190 -190
- package/skills/v8-image-processing/agents/openai.yaml +4 -4
- package/skills/v8-image-processing/references/api-reference.md +623 -623
- package/skills/v8-menu-buttons/SKILL.md +186 -186
- package/skills/v8-menu-buttons/references/progressive-01-2-/346/214/211/351/222/256/345/257/271/350/261/241-schema.md +222 -222
- package/skills/v8-menu-buttons/references/progressive-02-8-/346/250/241/345/274/217-f-/345/220/216/345/217/260/344/273/273/345/212/241/346/214/211/351/222/256-/351/225/277/344/273/273/345/212/241.md +228 -228
- package/skills/v8-menu-buttons/references/progressive-03-10-/345/217/215/346/250/241/345/274/217-/351/201/277/345/205/215.md +104 -104
- package/skills/v8-mongodb/SKILL.md +200 -200
- package/skills/v8-mq-mqtt/SKILL.md +178 -176
- package/skills/v8-mq-mqtt/references/mqtt-production.md +352 -342
- package/skills/v8-mq-mqtt/references/progressive-01-v8-mqtt-iot-/347/211/251/350/201/224/347/275/221.md +181 -181
- package/skills/v8-mq-mqtt/scripts/check-mqtt-skill-coverage.mjs +203 -203
- package/skills/v8-saas-multi-tenant/SKILL.md +305 -305
- package/skills/v8-security/SKILL.md +227 -210
- package/skills/v8-security/references/progressive-01-2-/346/235/203/351/231/220/346/240/241/351/252/214.md +200 -200
- package/skills/v8-security/references/progressive-02-7-/346/227/245/345/277/227/350/256/260/345/275/225.md +160 -160
- package/skills/v8-sql-query/SKILL.md +302 -302
- package/skills/v8-table-event/SKILL.md +176 -176
- package/skills/v8-table-event/references/progressive-01-informv8-js-/350/241/250/345/215/225/346/211/223/345/274/200/344/272/213/344/273/266.md +216 -216
- package/skills/v8-table-event/references/progressive-02-/345/211/215/347/253/257/344/272/213/344/273/266/345/220/215-v8-eventname-/345/217/257/350/203/275/347/232/204/345/200/274.md +46 -46
- package/skills/v8-tcp-integration/SKILL.md +158 -147
- package/skills/v8-tcp-integration/agents/openai.yaml +4 -4
- package/skills/v8-template-engine/SKILL.md +167 -167
- package/skills/v8-utilities/SKILL.md +104 -104
- package/skills/v8-utilities/references/client-api-index.md +143 -143
- package/skills/v8-utilities/references/platform-http-routes.md +83 -83
- package/skills/v8-utilities/references/server-api-index.md +188 -188
- package/skills/v8-workflow/SKILL.md +252 -252
- package/skills/v8-workflow/references/progressive-01-/350/212/202/347/202/271/345/274/200/345/247/213-v8-/344/272/213/344/273/266.md +180 -180
- package/skills/v8-workflow/references/workflow-configuration.md +49 -49
- package/skills/vision-engine/SKILL.md +160 -160
- package/skills/vision-engine/agents/openai.yaml +4 -4
- package/skills/vision-engine/references/architecture-and-acceptance.md +194 -194
- package/skills/workspace-conventions/SKILL.md +13 -13
- package/skills/workspace-conventions/references/progressive-03-cli-/344/270/216-ide-/346/217/222/344/273/266/351/224/231/347/211/210/345/205/261/345/255/230/347/272/246/345/256/232.md +2 -2
|
@@ -1,261 +1,261 @@
|
|
|
1
|
-
# microi-uniapp-frontend 详细参考 1
|
|
2
|
-
|
|
3
|
-
> 按需读取;本文件由 SKILL.md 的原章节无损拆分。
|
|
4
|
-
|
|
5
|
-
<!-- microi-progressive:chunk id=microi-uniapp-frontend-010 sha256=
|
|
6
|
-
## 移动端分类/双栏列表独立滚动
|
|
7
|
-
|
|
8
|
-
商品分类、知识库分类、通讯录分组、资产分类等“左侧分类 + 右侧列表”的移动端页面,根节点必须固定在一个视口内,不能让整页和内部列表同时滚动。
|
|
9
|
-
|
|
10
|
-
- 根页面使用有界视口高度、`overflow:hidden; display:flex; flex-direction:column;`;H5 使用 `100dvh` 或共享可见高度变量,保留 `100vh` 旧端兜底。
|
|
11
|
-
- 分类主体使用 `flex:1; min-height:0; display:flex;`。导航在根 flex 流内时不再加 tabBar 占位;导航覆盖正文时,才由共享壳预留一次实测总高度(已经包含安全区)。
|
|
12
|
-
- 左侧分类和右侧列表分别用 `scroll-view scroll-y`,高度来自父级 `height:100%` / `flex:1; min-height:0`,不要用整页滚动承载右侧商品列表。
|
|
13
|
-
- 右侧分页必须绑定 `@scrolltolower`,设置合理 `lower-threshold`,并维护 `pageIndex/pageSize/loading/finished`,第一页重置列表,后续页追加列表。
|
|
14
|
-
- 切换左侧分类或顶部专区时,必须重置分页状态并重新加载第一页;不能沿用旧分类的 `finished` 或 `pageIndex`。
|
|
15
|
-
- 验收截图要重点看底部:内容不能被 tabBar 压住,页面底部不能出现整页滚动留下的大块空隙。
|
|
16
|
-
|
|
17
|
-
参考结构:
|
|
18
|
-
|
|
19
|
-
```vue
|
|
20
|
-
<view class="page-category">
|
|
21
|
-
<view class="area-tabs">...</view>
|
|
22
|
-
<view class="cat-body">
|
|
23
|
-
<scroll-view class="cat-side" scroll-y>...</scroll-view>
|
|
24
|
-
<scroll-view class="cat-content" scroll-y lower-threshold="120" @scrolltolower="loadMore">...</scroll-view>
|
|
25
|
-
</view>
|
|
26
|
-
</view>
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
```scss
|
|
30
|
-
.page-category { height: 100vh; height: var(--mci-visible-height, 100dvh); overflow: hidden; display: flex; flex-direction: column; }
|
|
31
|
-
.cat-body { flex: 1; min-height: 0; display: flex; }
|
|
32
|
-
.cat-side { width: 176rpx; height: 100%; }
|
|
33
|
-
.cat-content { flex: 1; min-width: 0; height: 100%; }
|
|
34
|
-
// 本示例采用流内导航,导航自己占高度并消费安全区;覆盖式导航另由共享壳预留实测高度。
|
|
35
|
-
.category-nav { flex-shrink: 0; padding-bottom: var(--mci-safe-bottom, env(safe-area-inset-bottom)); }
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
<!-- /microi-progressive:chunk -->
|
|
39
|
-
<!-- microi-progressive:chunk id=microi-uniapp-frontend-011 sha256=
|
|
40
|
-
## 数据页必须使用骨架屏 Loading
|
|
41
|
-
|
|
42
|
-
任何依赖接口/数据库返回数据的移动端页面,都必须区分 `loading`、`data`、`empty`,并且首屏加载态必须使用骨架屏(Skeleton Screen)。接口请求结束前不能提前显示“暂无数据/暂无明细/空空如也”,也不能只用“图标 + 数据加载中...”或单独 spinner 作为页面级 loading。
|
|
43
|
-
|
|
44
|
-
- `loading` 初始值设为 `true`(或进入页面同步设为 `true`),请求 `finally` 中再置为 `false`;未登录、无权限、参数缺失等提前返回分支也必须关闭 `loading`。
|
|
45
|
-
- 首屏加载、切换 tab、筛选、搜索、分类、重新加载第一页时,应显示与最终版式接近的骨架:列表页用列表骨架,双列商品用网格骨架,详情页用详情骨架,首页 Banner/卡片区用对应区域骨架。
|
|
46
|
-
- 分页追加下一页时不能遮住已有数据,可在列表底部追加紧凑骨架行/骨架卡片;已有数据仍保持可阅读和可滚动。
|
|
47
|
-
- 空态必须使用 `!loading && list.length === 0`,不能直接写 `v-if="!list.length"`;空态可以用图标、文案和行动按钮,但只能在请求完成后出现。
|
|
48
|
-
- 请求失败时结束 loading,并给用户 toast、错误空态或可重试入口;不要静默失败后停在骨架屏,也不要把失败误显示成“暂无数据”。
|
|
49
|
-
- 通用组件可以保留 `DataState` 处理空态,但其 `loading` 分支必须渲染骨架屏,不得渲染加载文案作为主体。
|
|
50
|
-
- 骨架屏样式必须遵循 `microi.skills/ui-design/SKILL.md` 的骨架屏 Loading 设计规范:形态贴近最终内容、尺寸稳定、主题适配、动效克制,并支持弱化动效。
|
|
51
|
-
|
|
52
|
-
参考结构:
|
|
53
|
-
|
|
54
|
-
```vue
|
|
55
|
-
<SkeletonGrid v-if="loading && !list.length" :rows="6" />
|
|
56
|
-
<view v-for="item in list" :key="item.Id">...</view>
|
|
57
|
-
<SkeletonList v-if="loading && list.length" compact :rows="2" />
|
|
58
|
-
<DataState v-else-if="!list.length" empty-text="暂无数据" />
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
```js
|
|
62
|
-
const loading = ref(true);
|
|
63
|
-
const list = ref([]);
|
|
64
|
-
|
|
65
|
-
async function load() {
|
|
66
|
-
loading.value = true;
|
|
67
|
-
try {
|
|
68
|
-
const r = await queryList();
|
|
69
|
-
list.value = r.Code === 1 ? (r.Data || []) : [];
|
|
70
|
-
} finally {
|
|
71
|
-
loading.value = false;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
<!-- /microi-progressive:chunk -->
|
|
77
|
-
<!-- microi-progressive:chunk id=microi-uniapp-frontend-012 sha256=
|
|
78
|
-
## 移动端安全区必须兼容 iOS 与 Android
|
|
79
|
-
|
|
80
|
-
任何 UniApp/H5 移动端页面都必须同时适配 iPhone 刘海屏/Dynamic Island/Home Indicator、Android 状态栏/虚拟导航栏/手势条、微信/浏览器/WebView 容器差异。不要用固定 `20px/44px/64px` 直接硬编码顶部或底部间距。
|
|
81
|
-
|
|
82
|
-
- `manifest.json` / H5 模板必须确保 viewport 含 `viewport-fit=cover`,否则 iOS 的 `env(safe-area-inset-*)` 不会完整生效。
|
|
83
|
-
- 页面根节点使用最小高度或固定视口布局时,顶部内容、底部固定栏和内部滚动容器必须一起考虑安全区,不能只给根节点加 padding;有界 H5 壳优先动态可见高度,不能用 `min-height:100vh` 代替高度上限。
|
|
84
|
-
- 顶部自定义导航栏应结合 `uni.getSystemInfoSync().statusBarHeight` 和 CSS `env(safe-area-inset-top)`:状态栏占位负责不同系统高度,导航按钮和标题整体下移,返回按钮触摸区不能压到刘海/状态栏。
|
|
85
|
-
- 不能只依赖 `env(safe-area-inset-*)`。微信小程序、部分 Android WebView 或开发者工具中该值可能为 `0`;项目必须通过 `uni.getWindowInfo()`(旧端回退 `uni.getSystemInfoSync()`)读取 `statusBarHeight`、`safeArea` / `safeAreaInsets`,注入统一的 `--mci-safe-top`、`--mci-safe-bottom` 等页面壳变量。
|
|
86
|
-
- 微信小程序使用 `navigationStyle: custom` 时,必须读取 `uni.getMenuButtonBoundingClientRect()`(必要时回退 `wx.getMenuButtonBoundingClientRect()`),给顶部栏右侧预留 `windowWidth - capsule.left + gap`。登录、分享、状态角标、更多操作等任何按钮都不能进入右上角胶囊区域。
|
|
87
|
-
- 全屏弹层/工作台如果包含历史、新建、关闭等多个头部操作,必须先计算整组宽度;胶囊左侧不足时将整组放到胶囊底边以下,不得通过缩小触摸区、覆盖胶囊或截断标题硬塞。自动化测试应读取元素与胶囊 `boundingClientRect` 并断言不相交。
|
|
88
|
-
- 安全区实现必须集中在 `MciPage`、页面壳 composable/runtime 或全局布局中;禁止每页各自猜测 `20px/44px`。`pages.json` 中每个 `navigationStyle: custom` 页面都必须接入同一个页面壳,新增路由时同步纳入检查。
|
|
89
|
-
- 底部 `tabBar`、购买栏、提交栏、批量操作栏应在栏内消费统一的真实安全区。流内栏已经占据布局高度,正文不得再加整条栏占位;覆盖式 fixed 栏才预留一次栏的实测总高度,确保最后一条数据可见。
|
|
90
|
-
- 底部 fixed 元素应优先使用运行时 `--mci-safe-bottom`,以 CSS `env(safe-area-inset-bottom)` 作为 H5 兜底;底部导航、提交栏、弹出层和滚动容器必须引用同一变量,不能各算一套。
|
|
91
|
-
- 双栏分类页、聊天页、详情页带底部按钮时,内部 `scroll-view` 要用 `flex:1; min-height:0` 承载滚动。`fixedBarHeight` 若已经包含安全区,不再加一份 `env`;禁止根 padding、原生占位、正文 padding 和栏 padding 共同重复预留。
|
|
92
|
-
- H5 在 PC 手机壳模式下,fixed 顶栏/底栏仍要限制在手机壳宽度内;不能铺满整个桌面浏览器。
|
|
93
|
-
- 桌面预览没有真实手机手势区时底部安全区为 `0`;不能为了模仿手机外观硬塞 `34px/80rpx` 等假安全区。边框、阴影、装饰 Home Indicator 与系统安全区要分别处理。
|
|
94
|
-
- 验收必须至少覆盖一个 iPhone 刘海/灵动岛尺寸、一个 Android 高状态栏或虚拟导航栏尺寸、一个微信开发者工具真机模拟尺寸、一个 PC H5 手机壳尺寸;逐项截图检查顶部不被状态栏/胶囊遮挡、底部按钮不贴边、列表最后一项可见。不能只截图首页,必须按 `pages.json` 路由清单覆盖登录、Tab 页、详情、表单、弹层和管理页。
|
|
95
|
-
- 独占屏幕且需要支持手机侧滑返回的功能应使用独立页面路由。`onBackPress`/页面返回先消费当前页内部的键盘、对话框和抽屉状态;内部状态清空后才弹出当前页,不能让一次返回直接退出小程序或越过底层业务页。
|
|
96
|
-
|
|
97
|
-
<!-- /microi-progressive:chunk -->
|
|
98
|
-
<!-- microi-progressive:chunk id=microi-uniapp-frontend-013 sha256=
|
|
99
|
-
## 微信自定义组件的点击与拖动事件必须真机链路验收
|
|
100
|
-
|
|
101
|
-
- UniApp 可拖动浮动入口等自定义组件,不要给 `touchstart/touchmove/touchend/tap` 整组无差别添加 `.stop/.prevent`。这些修饰符会生成微信 `catchtouch* / catchtap`,部分 UniApp 自定义组件中可能吞掉事件桥,出现节点可见但点击和触摸方法完全不执行。
|
|
102
|
-
- 优先使用可正常分发的 `bindtouch* / bindtap`,在方法内部通过 10-12px 位移阈值区分短触与拖动;短触应在 `touchend` 直接执行主动作,`tap` 仅作鼠标/H5 兜底,拖动结束不得误触主动作。
|
|
103
|
-
- 导航失败必须提供可见提示并记录错误,禁止让点击失败表现为毫无反应。
|
|
104
|
-
- H5 的 DOM `.click()`、CDP 触摸和微信预览编译都不能证明小程序组件事件桥正常。交付前必须使用微信开发者工具或 `miniprogram-automator` 对真实节点派发触摸,并断言目标页面进入页面栈;同时抽查一个普通按钮,排除自动化工具自身失效。
|
|
105
|
-
|
|
106
|
-
参考样式:
|
|
107
|
-
|
|
108
|
-
```scss
|
|
109
|
-
.page-mobile {
|
|
110
|
-
min-height: 100vh;
|
|
111
|
-
padding-top: calc(24rpx + var(--mci-safe-top, env(safe-area-inset-top)));
|
|
112
|
-
padding-bottom: calc(112rpx + var(--mci-safe-bottom, env(safe-area-inset-bottom)));
|
|
113
|
-
box-sizing: border-box;
|
|
114
|
-
}
|
|
115
|
-
.mci-navbar {
|
|
116
|
-
padding-right: var(--mci-capsule-right, 0px);
|
|
117
|
-
}
|
|
118
|
-
.bottom-bar {
|
|
119
|
-
position: fixed;
|
|
120
|
-
left: 24rpx;
|
|
121
|
-
right: 24rpx;
|
|
122
|
-
bottom: calc(24rpx + var(--mci-safe-bottom, env(safe-area-inset-bottom)));
|
|
123
|
-
}
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
<!-- /microi-progressive:chunk -->
|
|
127
|
-
<!-- microi-progressive:chunk id=microi-uniapp-frontend-014 sha256=
|
|
128
|
-
## 列表型资料页必须提供完整管理动作
|
|
129
|
-
|
|
130
|
-
地址、联系人、收款方式、发票抬头、车辆、设备、证照、银行卡等用户维护型资料页,不能只展示简略列表。除非业务明确只读,移动端必须提供:
|
|
131
|
-
|
|
132
|
-
- 查看完整信息:点击卡片或“详情”打开详情页/弹层,显示列表里省略的所有关键字段。
|
|
133
|
-
- 新增和编辑:新增与编辑可以复用同一表单,编辑时要带 Id 并回填现有值。
|
|
134
|
-
- 删除:必须有二次确认,并校验当前用户只能删除自己的资料;删除成功后刷新列表。
|
|
135
|
-
- 默认/启用类状态:同一用户只允许一个默认值时,后端保存接口要负责互斥清理,前端不能只改本地 UI。
|
|
136
|
-
- 权限与接口:后端接口必须用 token/当前用户校验所有权,不能信任前端传来的 MemberId/UserId。
|
|
137
|
-
- 跨会员但属于当前业务流程可见的数据(例如订单买家查看卖家收款方式、交易双方资料、售后处理信息)必须由订单/售后等业务 ApiEngine 在完成订单参与者权限校验后返回;前端不能用通用 `formEngineGet` 直接查对方会员表数据,因为移动端通用查询通常会自动追加当前会员隔离条件。
|
|
138
|
-
- 空态行动:没有数据时给出新增入口,但仍要遵守上面的加载态规则。
|
|
139
|
-
|
|
140
|
-
<!-- /microi-progressive:chunk -->
|
|
141
|
-
<!-- microi-progressive:chunk id=microi-uniapp-frontend-015 sha256=
|
|
142
|
-
## 移动端资产/奖励流水展示
|
|
143
|
-
|
|
144
|
-
收益明细、积分明细、奖励明细、充值记录、订单流水等页面要面向用户展示“发生了什么”和“是否到账”,不要直接暴露后台调试字段。
|
|
145
|
-
|
|
146
|
-
- 每条记录必须显示完整时间(至少 `yyyy-MM-dd HH:mm:ss` 或同等精度),不能只显示日期加分钟片段。
|
|
147
|
-
- 有入账状态的记录必须用清晰标签展示,例如“待入账 / 已入账”;待入账金额颜色要与已入账区分,但仍保持可读。
|
|
148
|
-
- 推荐显示:类型、金额、完整时间、状态、贡献会员/交易对象、业务资产短码(如卡号/券码)和必要的标题。
|
|
149
|
-
- 不要在移动端直接显示内部 `RelOrderId`、服务费订单号、数据库 Id、调试来源操作、规则比例说明等后台字段,除非页面是面向运维的后台工具。
|
|
150
|
-
- 后端接口应先把 `TypeLabel`、`SettleStatusLabel`、`DisplayTime`、`ContributorName`、`CardNo` 等字段整理好,前端只做轻展示,避免多个页面各自拼接导致重复或口径不一致。
|
|
151
|
-
|
|
152
|
-
<!-- /microi-progressive:chunk -->
|
|
153
|
-
<!-- microi-progressive:chunk id=microi-uniapp-frontend-016 sha256=
|
|
154
|
-
## H5 在 PC 浏览器必须自动模拟移动端
|
|
155
|
-
|
|
156
|
-
移动端 UniApp H5 被 PC 浏览器访问时,不能按桌面宽屏铺满。必须在全局样式里用媒体查询生成手机预览壳。
|
|
157
|
-
|
|
158
|
-
基础要求:
|
|
159
|
-
|
|
160
|
-
- 桌面预览把内屏居中并限制到常见手机宽度,例如 `430px`;预览条件综合宽度、输入能力或项目运行时设备标记,不能仅按 `min-width:768px` 把手机横屏当桌面。下面媒体查询是精细指针桌面示例,项目还需验证移动设备仿真和真实设备判断。
|
|
161
|
-
- `html, body` 使用克制的桌面背景,`uni-app` 内保持移动端页面本身背景。
|
|
162
|
-
- 如果项目或主题给 `body.theme-light`、`body.theme-dark` 写了背景色,PC 媒体查询必须显式覆盖,避免手机壳外侧仍显示暗色或项目内装饰背景。
|
|
163
|
-
- 同步约束页面壳及 `uni-page / uni-page-wrapper / uni-page-body` 中实际参与布局的包装层:`min-height:0; min-width:0`。头部和导航不收缩,剩余高度留给正文;不能把 `uni-page-body` 写成整屏高后再追加导航。
|
|
164
|
-
- 先确定导航是流内还是覆盖式。流内栏使用 `flex-shrink:0`,正文不加整栏占位;覆盖式栏的宽、高、底边和唯一占位由共享壳负责。原生 `uni-tabbar` 的平台占位存在时不能再叠自定义占位。
|
|
165
|
-
- 有桌面外边距或矮屏壳时,栏必须贴壳内屏底边,不是外窗 `bottom:0`。为覆盖式栏建立属于内屏的定位包含块,或根据其真实矩形定位;不要同时给原生 tabBar 外层和内层重复 `fixed`。
|
|
166
|
-
- `rpx` 按设备宽度计算,不自动跟随 CSS 手机壳宽度。`pages.json.globalStyle` 的最大换算宽度和基准宽度应与预览策略一致,例如 767/430;检查 768、960 和 4K 外窗的实际换算结果。全宽使用 `100%` 或 flex,不能用 `750rpx`。参见 [DCloud 宽屏适配](https://uniapp.dcloud.io/tutorial/adapt.html)。
|
|
167
|
-
- 页面内 `position: fixed` 的装饰背景(如 aurora、粒子、全屏渐变)在 PC 壳模式下必须收回到 `uni-app/uni-page-body` 内,不能覆盖整块桌面背景。
|
|
168
|
-
|
|
169
|
-
自定义流内导航参考结构(选择该模式后,不再并列渲染原生导航):
|
|
170
|
-
|
|
171
|
-
```html
|
|
172
|
-
<main class="mci-h5-viewport" data-app-viewport>
|
|
173
|
-
<header class="mci-preview-header">移动端预览</header>
|
|
174
|
-
<section class="mci-page-scroll" data-page-scroll>页面内容</section>
|
|
175
|
-
<nav class="mci-bottom-nav" data-bottom-nav>图标与菜单触摸区</nav>
|
|
176
|
-
</main>
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
参考样式:
|
|
180
|
-
|
|
181
|
-
```scss
|
|
182
|
-
html, body { margin: 0; height: 100%; overflow: hidden; }
|
|
183
|
-
.mci-h5-viewport {
|
|
184
|
-
box-sizing: border-box;
|
|
185
|
-
width: 100%; height: 100vh;
|
|
186
|
-
height: var(--mci-visible-height, 100dvh);
|
|
187
|
-
min-height: 0;
|
|
188
|
-
display: flex; flex-direction: column; overflow: hidden;
|
|
189
|
-
background: var(--app-bg-base, #F7F8FB);
|
|
190
|
-
}
|
|
191
|
-
.mci-preview-header { display: none; flex-shrink: 0; }
|
|
192
|
-
.mci-page-scroll { flex: 1; min-height: 0; min-width: 0; overflow-y: auto; }
|
|
193
|
-
.mci-bottom-nav {
|
|
194
|
-
flex-shrink: 0; box-sizing: border-box;
|
|
195
|
-
padding-bottom: var(--mci-safe-bottom, env(safe-area-inset-bottom, 0px));
|
|
196
|
-
}
|
|
197
|
-
@media screen and (min-width: 768px) and (hover: hover) and (pointer: fine) {
|
|
198
|
-
body { display: grid; place-items: center; background: #F3F5F9; }
|
|
199
|
-
.mci-h5-viewport {
|
|
200
|
-
--mci-safe-bottom: 0px; // 桌面预览没有手机系统手势区,不伪造安全区。
|
|
201
|
-
width: 430px;
|
|
202
|
-
height: calc(100vh - 32px); height: calc(100dvh - 32px);
|
|
203
|
-
max-height: 900px;
|
|
204
|
-
border-radius: 24px;
|
|
205
|
-
box-shadow: 0 18px 54px rgba(28, 36, 52, .16);
|
|
206
|
-
}
|
|
207
|
-
.mci-preview-header { display: block; }
|
|
208
|
-
}
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
真实 UniApp 页面还应检查框架包装层高度和原生 tabBar 占位。这个结构示例不授权业务页覆盖所有 `uni-*` 标签,也不适用于必须使用文档滚动的页面;文档滚动模式必须另行证明根滚动是唯一 owner、导航跟随可见视口且尾部占位仅一份。
|
|
212
|
-
|
|
213
|
-
### 导航贴底与剩余空间的真实断言
|
|
214
|
-
|
|
215
|
-
H5 安全区必须来自 CSS `env(safe-area-inset-bottom)` 等浏览器权威来源。`screenHeight - windowHeight` 与 `screen.height - innerHeight` 包含外窗、工具栏和缩放差异,禁止转换为安全区 padding。App/小程序的权威 inset 可以为 `0`,只能在值缺失时按明确平台契约处理,不能用 `inset || guessedFallback` 将零替换。桌面非最大化窗口和缩放必须纳入验收,物理屏幕与视口不同也应保持导航内栏高度有界。
|
|
216
|
-
|
|
217
|
-
下列例子测量自定义流内导航;选择器按项目真实结构替换,目标边界必须是**内屏**而不是带边框的装饰壳。设计值在测试开始前固定,不能根据异常画面扩大阈值:
|
|
218
|
-
|
|
219
|
-
```js
|
|
220
|
-
const geometry = await page.evaluate(() => {
|
|
221
|
-
const rect = node => {
|
|
222
|
-
const r = node.getBoundingClientRect();
|
|
223
|
-
return { top: r.top, bottom: r.bottom, left: r.left, right: r.right, height: r.height };
|
|
224
|
-
};
|
|
225
|
-
const screen = document.querySelector('[data-app-viewport]');
|
|
226
|
-
const nav = document.querySelector('[data-bottom-nav]');
|
|
227
|
-
const scroll = document.querySelector('[data-page-scroll]');
|
|
228
|
-
if (!screen || !nav || !scroll) throw new Error('页面结构缺失');
|
|
229
|
-
const items = [...nav.querySelectorAll('[data-nav-item]')];
|
|
230
|
-
if (!items.length) throw new Error('导航菜单缺失');
|
|
231
|
-
return {
|
|
232
|
-
screen: rect(screen), nav: rect(nav), scroll: rect(scroll), items: items.map(rect),
|
|
233
|
-
safeBottom: parseFloat(getComputedStyle(nav).paddingBottom) || 0,
|
|
234
|
-
rootOverflow: document.scrollingElement.scrollHeight - document.scrollingElement.clientHeight
|
|
235
|
-
};
|
|
236
|
-
});
|
|
237
|
-
expect(Math.abs(geometry.nav.bottom - geometry.screen.bottom)).toBeLessThanOrEqual(2);
|
|
238
|
-
expect(geometry.nav.left).toBeGreaterThanOrEqual(geometry.screen.left - 2);
|
|
239
|
-
expect(geometry.nav.right).toBeLessThanOrEqual(geometry.screen.right + 2);
|
|
240
|
-
expect(geometry.scroll.bottom).toBeLessThanOrEqual(geometry.nav.top + 2);
|
|
241
|
-
expect(geometry.rootOverflow).toBeLessThanOrEqual(2);
|
|
242
|
-
expect(geometry.nav.height).toBeLessThanOrEqual(designNavContentHeight + geometry.safeBottom + 2);
|
|
243
|
-
const lastItemBottom = Math.max(...geometry.items.map(item => item.bottom));
|
|
244
|
-
expect(geometry.nav.bottom - lastItemBottom)
|
|
245
|
-
.toBeLessThanOrEqual(geometry.safeBottom + designNavInnerBottomGap + 2);
|
|
246
|
-
await page.screenshot({ path: screenshotPath, fullPage: false });
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
`safeBottom` 在此示例是 CSS 计算结果,不代表系统安全区来源已经可信。测试仍须核对运行时安全值、同一个值的唯一消费位置和桌面为零;不能用一个错误的巨大 padding 放宽几何门禁。短内容允许正文留白,禁止的是**导航下方**无业务依据的大块剩余区域。
|
|
250
|
-
|
|
251
|
-
| 场景 | 必须断言 |
|
|
252
|
-
|---|---|
|
|
253
|
-
| 三个主 Tab、短内容/空态 | 导航底边贴内屏,内栏高度有界,图标文字可见且触摸区可点 |
|
|
254
|
-
| 长内容滚动中/到底、切回 Tab | 导航位置不漂移,最后一项可达且未遮挡,壳外根滚动不变化 |
|
|
255
|
-
| 桌面 1024×600 / 1366×768 / 1920×1080 / 4K | 内屏在视口内,导航贴壳底;rpx 不随外窗放大,正文只有一个 owner |
|
|
256
|
-
| 手机 375×812 / 430×932、767/768 断点、横屏与旋转 | 移动模式去壳,内屏铺满可见区域;旋转后重测安全区和底边 |
|
|
257
|
-
| 键盘打开/关闭、浏览器栏展开/收起 | 焦点与操作可见,关闭后恢复底边,无残留占位或第二条滚动条 |
|
|
258
|
-
|
|
259
|
-
H5 键盘可能改变 visual viewport 而不改变 layout viewport;`100dvh` 不是所有键盘模式的保证。共享壳按目标浏览器处理 `visualViewport` 尺寸/偏移与 resize/恢复,原生端按配置的键盘模式测量;真机 iOS/Android 另验。缩小 Playwright 视口只证明 resize 分支,不等于软键盘实测。参考 [W3C Viewport 交互部件规则](https://www.w3.org/TR/css-viewport-1/#interactive-widget-section)。
|
|
260
|
-
|
|
261
|
-
<!-- /microi-progressive:chunk -->
|
|
1
|
+
# microi-uniapp-frontend 详细参考 1
|
|
2
|
+
|
|
3
|
+
> 按需读取;本文件由 SKILL.md 的原章节无损拆分。
|
|
4
|
+
|
|
5
|
+
<!-- microi-progressive:chunk id=microi-uniapp-frontend-010 sha256=d662fcd325e57ad4ac1f0e1c5e1b988909b68b82e8d894493214227498db0c93 -->
|
|
6
|
+
## 移动端分类/双栏列表独立滚动
|
|
7
|
+
|
|
8
|
+
商品分类、知识库分类、通讯录分组、资产分类等“左侧分类 + 右侧列表”的移动端页面,根节点必须固定在一个视口内,不能让整页和内部列表同时滚动。
|
|
9
|
+
|
|
10
|
+
- 根页面使用有界视口高度、`overflow:hidden; display:flex; flex-direction:column;`;H5 使用 `100dvh` 或共享可见高度变量,保留 `100vh` 旧端兜底。
|
|
11
|
+
- 分类主体使用 `flex:1; min-height:0; display:flex;`。导航在根 flex 流内时不再加 tabBar 占位;导航覆盖正文时,才由共享壳预留一次实测总高度(已经包含安全区)。
|
|
12
|
+
- 左侧分类和右侧列表分别用 `scroll-view scroll-y`,高度来自父级 `height:100%` / `flex:1; min-height:0`,不要用整页滚动承载右侧商品列表。
|
|
13
|
+
- 右侧分页必须绑定 `@scrolltolower`,设置合理 `lower-threshold`,并维护 `pageIndex/pageSize/loading/finished`,第一页重置列表,后续页追加列表。
|
|
14
|
+
- 切换左侧分类或顶部专区时,必须重置分页状态并重新加载第一页;不能沿用旧分类的 `finished` 或 `pageIndex`。
|
|
15
|
+
- 验收截图要重点看底部:内容不能被 tabBar 压住,页面底部不能出现整页滚动留下的大块空隙。
|
|
16
|
+
|
|
17
|
+
参考结构:
|
|
18
|
+
|
|
19
|
+
```vue
|
|
20
|
+
<view class="page-category">
|
|
21
|
+
<view class="area-tabs">...</view>
|
|
22
|
+
<view class="cat-body">
|
|
23
|
+
<scroll-view class="cat-side" scroll-y>...</scroll-view>
|
|
24
|
+
<scroll-view class="cat-content" scroll-y lower-threshold="120" @scrolltolower="loadMore">...</scroll-view>
|
|
25
|
+
</view>
|
|
26
|
+
</view>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
```scss
|
|
30
|
+
.page-category { height: 100vh; height: var(--mci-visible-height, 100dvh); overflow: hidden; display: flex; flex-direction: column; }
|
|
31
|
+
.cat-body { flex: 1; min-height: 0; display: flex; }
|
|
32
|
+
.cat-side { width: 176rpx; height: 100%; }
|
|
33
|
+
.cat-content { flex: 1; min-width: 0; height: 100%; }
|
|
34
|
+
// 本示例采用流内导航,导航自己占高度并消费安全区;覆盖式导航另由共享壳预留实测高度。
|
|
35
|
+
.category-nav { flex-shrink: 0; padding-bottom: var(--mci-safe-bottom, env(safe-area-inset-bottom)); }
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
<!-- /microi-progressive:chunk -->
|
|
39
|
+
<!-- microi-progressive:chunk id=microi-uniapp-frontend-011 sha256=a28fba298274b738ef9039c6bd6a1707468687e2ae9644a819736374586749e9 -->
|
|
40
|
+
## 数据页必须使用骨架屏 Loading
|
|
41
|
+
|
|
42
|
+
任何依赖接口/数据库返回数据的移动端页面,都必须区分 `loading`、`data`、`empty`,并且首屏加载态必须使用骨架屏(Skeleton Screen)。接口请求结束前不能提前显示“暂无数据/暂无明细/空空如也”,也不能只用“图标 + 数据加载中...”或单独 spinner 作为页面级 loading。
|
|
43
|
+
|
|
44
|
+
- `loading` 初始值设为 `true`(或进入页面同步设为 `true`),请求 `finally` 中再置为 `false`;未登录、无权限、参数缺失等提前返回分支也必须关闭 `loading`。
|
|
45
|
+
- 首屏加载、切换 tab、筛选、搜索、分类、重新加载第一页时,应显示与最终版式接近的骨架:列表页用列表骨架,双列商品用网格骨架,详情页用详情骨架,首页 Banner/卡片区用对应区域骨架。
|
|
46
|
+
- 分页追加下一页时不能遮住已有数据,可在列表底部追加紧凑骨架行/骨架卡片;已有数据仍保持可阅读和可滚动。
|
|
47
|
+
- 空态必须使用 `!loading && list.length === 0`,不能直接写 `v-if="!list.length"`;空态可以用图标、文案和行动按钮,但只能在请求完成后出现。
|
|
48
|
+
- 请求失败时结束 loading,并给用户 toast、错误空态或可重试入口;不要静默失败后停在骨架屏,也不要把失败误显示成“暂无数据”。
|
|
49
|
+
- 通用组件可以保留 `DataState` 处理空态,但其 `loading` 分支必须渲染骨架屏,不得渲染加载文案作为主体。
|
|
50
|
+
- 骨架屏样式必须遵循 `microi.skills/ui-design/SKILL.md` 的骨架屏 Loading 设计规范:形态贴近最终内容、尺寸稳定、主题适配、动效克制,并支持弱化动效。
|
|
51
|
+
|
|
52
|
+
参考结构:
|
|
53
|
+
|
|
54
|
+
```vue
|
|
55
|
+
<SkeletonGrid v-if="loading && !list.length" :rows="6" />
|
|
56
|
+
<view v-for="item in list" :key="item.Id">...</view>
|
|
57
|
+
<SkeletonList v-if="loading && list.length" compact :rows="2" />
|
|
58
|
+
<DataState v-else-if="!list.length" empty-text="暂无数据" />
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
const loading = ref(true);
|
|
63
|
+
const list = ref([]);
|
|
64
|
+
|
|
65
|
+
async function load() {
|
|
66
|
+
loading.value = true;
|
|
67
|
+
try {
|
|
68
|
+
const r = await queryList();
|
|
69
|
+
list.value = r.Code === 1 ? (r.Data || []) : [];
|
|
70
|
+
} finally {
|
|
71
|
+
loading.value = false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
<!-- /microi-progressive:chunk -->
|
|
77
|
+
<!-- microi-progressive:chunk id=microi-uniapp-frontend-012 sha256=fe012b3e626a42152e6cbdb8df3f49f5ab71ed3d36dc4e145cc37d983624fc18 -->
|
|
78
|
+
## 移动端安全区必须兼容 iOS 与 Android
|
|
79
|
+
|
|
80
|
+
任何 UniApp/H5 移动端页面都必须同时适配 iPhone 刘海屏/Dynamic Island/Home Indicator、Android 状态栏/虚拟导航栏/手势条、微信/浏览器/WebView 容器差异。不要用固定 `20px/44px/64px` 直接硬编码顶部或底部间距。
|
|
81
|
+
|
|
82
|
+
- `manifest.json` / H5 模板必须确保 viewport 含 `viewport-fit=cover`,否则 iOS 的 `env(safe-area-inset-*)` 不会完整生效。
|
|
83
|
+
- 页面根节点使用最小高度或固定视口布局时,顶部内容、底部固定栏和内部滚动容器必须一起考虑安全区,不能只给根节点加 padding;有界 H5 壳优先动态可见高度,不能用 `min-height:100vh` 代替高度上限。
|
|
84
|
+
- 顶部自定义导航栏应结合 `uni.getSystemInfoSync().statusBarHeight` 和 CSS `env(safe-area-inset-top)`:状态栏占位负责不同系统高度,导航按钮和标题整体下移,返回按钮触摸区不能压到刘海/状态栏。
|
|
85
|
+
- 不能只依赖 `env(safe-area-inset-*)`。微信小程序、部分 Android WebView 或开发者工具中该值可能为 `0`;项目必须通过 `uni.getWindowInfo()`(旧端回退 `uni.getSystemInfoSync()`)读取 `statusBarHeight`、`safeArea` / `safeAreaInsets`,注入统一的 `--mci-safe-top`、`--mci-safe-bottom` 等页面壳变量。
|
|
86
|
+
- 微信小程序使用 `navigationStyle: custom` 时,必须读取 `uni.getMenuButtonBoundingClientRect()`(必要时回退 `wx.getMenuButtonBoundingClientRect()`),给顶部栏右侧预留 `windowWidth - capsule.left + gap`。登录、分享、状态角标、更多操作等任何按钮都不能进入右上角胶囊区域。
|
|
87
|
+
- 全屏弹层/工作台如果包含历史、新建、关闭等多个头部操作,必须先计算整组宽度;胶囊左侧不足时将整组放到胶囊底边以下,不得通过缩小触摸区、覆盖胶囊或截断标题硬塞。自动化测试应读取元素与胶囊 `boundingClientRect` 并断言不相交。
|
|
88
|
+
- 安全区实现必须集中在 `MciPage`、页面壳 composable/runtime 或全局布局中;禁止每页各自猜测 `20px/44px`。`pages.json` 中每个 `navigationStyle: custom` 页面都必须接入同一个页面壳,新增路由时同步纳入检查。
|
|
89
|
+
- 底部 `tabBar`、购买栏、提交栏、批量操作栏应在栏内消费统一的真实安全区。流内栏已经占据布局高度,正文不得再加整条栏占位;覆盖式 fixed 栏才预留一次栏的实测总高度,确保最后一条数据可见。
|
|
90
|
+
- 底部 fixed 元素应优先使用运行时 `--mci-safe-bottom`,以 CSS `env(safe-area-inset-bottom)` 作为 H5 兜底;底部导航、提交栏、弹出层和滚动容器必须引用同一变量,不能各算一套。
|
|
91
|
+
- 双栏分类页、聊天页、详情页带底部按钮时,内部 `scroll-view` 要用 `flex:1; min-height:0` 承载滚动。`fixedBarHeight` 若已经包含安全区,不再加一份 `env`;禁止根 padding、原生占位、正文 padding 和栏 padding 共同重复预留。
|
|
92
|
+
- H5 在 PC 手机壳模式下,fixed 顶栏/底栏仍要限制在手机壳宽度内;不能铺满整个桌面浏览器。
|
|
93
|
+
- 桌面预览没有真实手机手势区时底部安全区为 `0`;不能为了模仿手机外观硬塞 `34px/80rpx` 等假安全区。边框、阴影、装饰 Home Indicator 与系统安全区要分别处理。
|
|
94
|
+
- 验收必须至少覆盖一个 iPhone 刘海/灵动岛尺寸、一个 Android 高状态栏或虚拟导航栏尺寸、一个微信开发者工具真机模拟尺寸、一个 PC H5 手机壳尺寸;逐项截图检查顶部不被状态栏/胶囊遮挡、底部按钮不贴边、列表最后一项可见。不能只截图首页,必须按 `pages.json` 路由清单覆盖登录、Tab 页、详情、表单、弹层和管理页。
|
|
95
|
+
- 独占屏幕且需要支持手机侧滑返回的功能应使用独立页面路由。`onBackPress`/页面返回先消费当前页内部的键盘、对话框和抽屉状态;内部状态清空后才弹出当前页,不能让一次返回直接退出小程序或越过底层业务页。
|
|
96
|
+
|
|
97
|
+
<!-- /microi-progressive:chunk -->
|
|
98
|
+
<!-- microi-progressive:chunk id=microi-uniapp-frontend-013 sha256=591a8e5a3e33cfcdb102abf56ebc6eeb5c5896d621442c30e734f455d625842c -->
|
|
99
|
+
## 微信自定义组件的点击与拖动事件必须真机链路验收
|
|
100
|
+
|
|
101
|
+
- UniApp 可拖动浮动入口等自定义组件,不要给 `touchstart/touchmove/touchend/tap` 整组无差别添加 `.stop/.prevent`。这些修饰符会生成微信 `catchtouch* / catchtap`,部分 UniApp 自定义组件中可能吞掉事件桥,出现节点可见但点击和触摸方法完全不执行。
|
|
102
|
+
- 优先使用可正常分发的 `bindtouch* / bindtap`,在方法内部通过 10-12px 位移阈值区分短触与拖动;短触应在 `touchend` 直接执行主动作,`tap` 仅作鼠标/H5 兜底,拖动结束不得误触主动作。
|
|
103
|
+
- 导航失败必须提供可见提示并记录错误,禁止让点击失败表现为毫无反应。
|
|
104
|
+
- H5 的 DOM `.click()`、CDP 触摸和微信预览编译都不能证明小程序组件事件桥正常。交付前必须使用微信开发者工具或 `miniprogram-automator` 对真实节点派发触摸,并断言目标页面进入页面栈;同时抽查一个普通按钮,排除自动化工具自身失效。
|
|
105
|
+
|
|
106
|
+
参考样式:
|
|
107
|
+
|
|
108
|
+
```scss
|
|
109
|
+
.page-mobile {
|
|
110
|
+
min-height: 100vh;
|
|
111
|
+
padding-top: calc(24rpx + var(--mci-safe-top, env(safe-area-inset-top)));
|
|
112
|
+
padding-bottom: calc(112rpx + var(--mci-safe-bottom, env(safe-area-inset-bottom)));
|
|
113
|
+
box-sizing: border-box;
|
|
114
|
+
}
|
|
115
|
+
.mci-navbar {
|
|
116
|
+
padding-right: var(--mci-capsule-right, 0px);
|
|
117
|
+
}
|
|
118
|
+
.bottom-bar {
|
|
119
|
+
position: fixed;
|
|
120
|
+
left: 24rpx;
|
|
121
|
+
right: 24rpx;
|
|
122
|
+
bottom: calc(24rpx + var(--mci-safe-bottom, env(safe-area-inset-bottom)));
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
<!-- /microi-progressive:chunk -->
|
|
127
|
+
<!-- microi-progressive:chunk id=microi-uniapp-frontend-014 sha256=62f20b920f2365d9f2f5062218b10b17aa181ccb3ae5d2260f795e086355f678 -->
|
|
128
|
+
## 列表型资料页必须提供完整管理动作
|
|
129
|
+
|
|
130
|
+
地址、联系人、收款方式、发票抬头、车辆、设备、证照、银行卡等用户维护型资料页,不能只展示简略列表。除非业务明确只读,移动端必须提供:
|
|
131
|
+
|
|
132
|
+
- 查看完整信息:点击卡片或“详情”打开详情页/弹层,显示列表里省略的所有关键字段。
|
|
133
|
+
- 新增和编辑:新增与编辑可以复用同一表单,编辑时要带 Id 并回填现有值。
|
|
134
|
+
- 删除:必须有二次确认,并校验当前用户只能删除自己的资料;删除成功后刷新列表。
|
|
135
|
+
- 默认/启用类状态:同一用户只允许一个默认值时,后端保存接口要负责互斥清理,前端不能只改本地 UI。
|
|
136
|
+
- 权限与接口:后端接口必须用 token/当前用户校验所有权,不能信任前端传来的 MemberId/UserId。
|
|
137
|
+
- 跨会员但属于当前业务流程可见的数据(例如订单买家查看卖家收款方式、交易双方资料、售后处理信息)必须由订单/售后等业务 ApiEngine 在完成订单参与者权限校验后返回;前端不能用通用 `formEngineGet` 直接查对方会员表数据,因为移动端通用查询通常会自动追加当前会员隔离条件。
|
|
138
|
+
- 空态行动:没有数据时给出新增入口,但仍要遵守上面的加载态规则。
|
|
139
|
+
|
|
140
|
+
<!-- /microi-progressive:chunk -->
|
|
141
|
+
<!-- microi-progressive:chunk id=microi-uniapp-frontend-015 sha256=d8e9280b5127d7dafd4dcb83b22bdb379fef39eac1e2e1b2e37f1c064cfe7fc6 -->
|
|
142
|
+
## 移动端资产/奖励流水展示
|
|
143
|
+
|
|
144
|
+
收益明细、积分明细、奖励明细、充值记录、订单流水等页面要面向用户展示“发生了什么”和“是否到账”,不要直接暴露后台调试字段。
|
|
145
|
+
|
|
146
|
+
- 每条记录必须显示完整时间(至少 `yyyy-MM-dd HH:mm:ss` 或同等精度),不能只显示日期加分钟片段。
|
|
147
|
+
- 有入账状态的记录必须用清晰标签展示,例如“待入账 / 已入账”;待入账金额颜色要与已入账区分,但仍保持可读。
|
|
148
|
+
- 推荐显示:类型、金额、完整时间、状态、贡献会员/交易对象、业务资产短码(如卡号/券码)和必要的标题。
|
|
149
|
+
- 不要在移动端直接显示内部 `RelOrderId`、服务费订单号、数据库 Id、调试来源操作、规则比例说明等后台字段,除非页面是面向运维的后台工具。
|
|
150
|
+
- 后端接口应先把 `TypeLabel`、`SettleStatusLabel`、`DisplayTime`、`ContributorName`、`CardNo` 等字段整理好,前端只做轻展示,避免多个页面各自拼接导致重复或口径不一致。
|
|
151
|
+
|
|
152
|
+
<!-- /microi-progressive:chunk -->
|
|
153
|
+
<!-- microi-progressive:chunk id=microi-uniapp-frontend-016 sha256=ef64ab9e559d2d0d29a125a0ba2d35296f6aebea0a898c86a6883f8987ad5a40 -->
|
|
154
|
+
## H5 在 PC 浏览器必须自动模拟移动端
|
|
155
|
+
|
|
156
|
+
移动端 UniApp H5 被 PC 浏览器访问时,不能按桌面宽屏铺满。必须在全局样式里用媒体查询生成手机预览壳。
|
|
157
|
+
|
|
158
|
+
基础要求:
|
|
159
|
+
|
|
160
|
+
- 桌面预览把内屏居中并限制到常见手机宽度,例如 `430px`;预览条件综合宽度、输入能力或项目运行时设备标记,不能仅按 `min-width:768px` 把手机横屏当桌面。下面媒体查询是精细指针桌面示例,项目还需验证移动设备仿真和真实设备判断。
|
|
161
|
+
- `html, body` 使用克制的桌面背景,`uni-app` 内保持移动端页面本身背景。
|
|
162
|
+
- 如果项目或主题给 `body.theme-light`、`body.theme-dark` 写了背景色,PC 媒体查询必须显式覆盖,避免手机壳外侧仍显示暗色或项目内装饰背景。
|
|
163
|
+
- 同步约束页面壳及 `uni-page / uni-page-wrapper / uni-page-body` 中实际参与布局的包装层:`min-height:0; min-width:0`。头部和导航不收缩,剩余高度留给正文;不能把 `uni-page-body` 写成整屏高后再追加导航。
|
|
164
|
+
- 先确定导航是流内还是覆盖式。流内栏使用 `flex-shrink:0`,正文不加整栏占位;覆盖式栏的宽、高、底边和唯一占位由共享壳负责。原生 `uni-tabbar` 的平台占位存在时不能再叠自定义占位。
|
|
165
|
+
- 有桌面外边距或矮屏壳时,栏必须贴壳内屏底边,不是外窗 `bottom:0`。为覆盖式栏建立属于内屏的定位包含块,或根据其真实矩形定位;不要同时给原生 tabBar 外层和内层重复 `fixed`。
|
|
166
|
+
- `rpx` 按设备宽度计算,不自动跟随 CSS 手机壳宽度。`pages.json.globalStyle` 的最大换算宽度和基准宽度应与预览策略一致,例如 767/430;检查 768、960 和 4K 外窗的实际换算结果。全宽使用 `100%` 或 flex,不能用 `750rpx`。参见 [DCloud 宽屏适配](https://uniapp.dcloud.io/tutorial/adapt.html)。
|
|
167
|
+
- 页面内 `position: fixed` 的装饰背景(如 aurora、粒子、全屏渐变)在 PC 壳模式下必须收回到 `uni-app/uni-page-body` 内,不能覆盖整块桌面背景。
|
|
168
|
+
|
|
169
|
+
自定义流内导航参考结构(选择该模式后,不再并列渲染原生导航):
|
|
170
|
+
|
|
171
|
+
```html
|
|
172
|
+
<main class="mci-h5-viewport" data-app-viewport>
|
|
173
|
+
<header class="mci-preview-header">移动端预览</header>
|
|
174
|
+
<section class="mci-page-scroll" data-page-scroll>页面内容</section>
|
|
175
|
+
<nav class="mci-bottom-nav" data-bottom-nav>图标与菜单触摸区</nav>
|
|
176
|
+
</main>
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
参考样式:
|
|
180
|
+
|
|
181
|
+
```scss
|
|
182
|
+
html, body { margin: 0; height: 100%; overflow: hidden; }
|
|
183
|
+
.mci-h5-viewport {
|
|
184
|
+
box-sizing: border-box;
|
|
185
|
+
width: 100%; height: 100vh;
|
|
186
|
+
height: var(--mci-visible-height, 100dvh);
|
|
187
|
+
min-height: 0;
|
|
188
|
+
display: flex; flex-direction: column; overflow: hidden;
|
|
189
|
+
background: var(--app-bg-base, #F7F8FB);
|
|
190
|
+
}
|
|
191
|
+
.mci-preview-header { display: none; flex-shrink: 0; }
|
|
192
|
+
.mci-page-scroll { flex: 1; min-height: 0; min-width: 0; overflow-y: auto; }
|
|
193
|
+
.mci-bottom-nav {
|
|
194
|
+
flex-shrink: 0; box-sizing: border-box;
|
|
195
|
+
padding-bottom: var(--mci-safe-bottom, env(safe-area-inset-bottom, 0px));
|
|
196
|
+
}
|
|
197
|
+
@media screen and (min-width: 768px) and (hover: hover) and (pointer: fine) {
|
|
198
|
+
body { display: grid; place-items: center; background: #F3F5F9; }
|
|
199
|
+
.mci-h5-viewport {
|
|
200
|
+
--mci-safe-bottom: 0px; // 桌面预览没有手机系统手势区,不伪造安全区。
|
|
201
|
+
width: 430px;
|
|
202
|
+
height: calc(100vh - 32px); height: calc(100dvh - 32px);
|
|
203
|
+
max-height: 900px;
|
|
204
|
+
border-radius: 24px;
|
|
205
|
+
box-shadow: 0 18px 54px rgba(28, 36, 52, .16);
|
|
206
|
+
}
|
|
207
|
+
.mci-preview-header { display: block; }
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
真实 UniApp 页面还应检查框架包装层高度和原生 tabBar 占位。这个结构示例不授权业务页覆盖所有 `uni-*` 标签,也不适用于必须使用文档滚动的页面;文档滚动模式必须另行证明根滚动是唯一 owner、导航跟随可见视口且尾部占位仅一份。
|
|
212
|
+
|
|
213
|
+
### 导航贴底与剩余空间的真实断言
|
|
214
|
+
|
|
215
|
+
H5 安全区必须来自 CSS `env(safe-area-inset-bottom)` 等浏览器权威来源。`screenHeight - windowHeight` 与 `screen.height - innerHeight` 包含外窗、工具栏和缩放差异,禁止转换为安全区 padding。App/小程序的权威 inset 可以为 `0`,只能在值缺失时按明确平台契约处理,不能用 `inset || guessedFallback` 将零替换。桌面非最大化窗口和缩放必须纳入验收,物理屏幕与视口不同也应保持导航内栏高度有界。
|
|
216
|
+
|
|
217
|
+
下列例子测量自定义流内导航;选择器按项目真实结构替换,目标边界必须是**内屏**而不是带边框的装饰壳。设计值在测试开始前固定,不能根据异常画面扩大阈值:
|
|
218
|
+
|
|
219
|
+
```js
|
|
220
|
+
const geometry = await page.evaluate(() => {
|
|
221
|
+
const rect = node => {
|
|
222
|
+
const r = node.getBoundingClientRect();
|
|
223
|
+
return { top: r.top, bottom: r.bottom, left: r.left, right: r.right, height: r.height };
|
|
224
|
+
};
|
|
225
|
+
const screen = document.querySelector('[data-app-viewport]');
|
|
226
|
+
const nav = document.querySelector('[data-bottom-nav]');
|
|
227
|
+
const scroll = document.querySelector('[data-page-scroll]');
|
|
228
|
+
if (!screen || !nav || !scroll) throw new Error('页面结构缺失');
|
|
229
|
+
const items = [...nav.querySelectorAll('[data-nav-item]')];
|
|
230
|
+
if (!items.length) throw new Error('导航菜单缺失');
|
|
231
|
+
return {
|
|
232
|
+
screen: rect(screen), nav: rect(nav), scroll: rect(scroll), items: items.map(rect),
|
|
233
|
+
safeBottom: parseFloat(getComputedStyle(nav).paddingBottom) || 0,
|
|
234
|
+
rootOverflow: document.scrollingElement.scrollHeight - document.scrollingElement.clientHeight
|
|
235
|
+
};
|
|
236
|
+
});
|
|
237
|
+
expect(Math.abs(geometry.nav.bottom - geometry.screen.bottom)).toBeLessThanOrEqual(2);
|
|
238
|
+
expect(geometry.nav.left).toBeGreaterThanOrEqual(geometry.screen.left - 2);
|
|
239
|
+
expect(geometry.nav.right).toBeLessThanOrEqual(geometry.screen.right + 2);
|
|
240
|
+
expect(geometry.scroll.bottom).toBeLessThanOrEqual(geometry.nav.top + 2);
|
|
241
|
+
expect(geometry.rootOverflow).toBeLessThanOrEqual(2);
|
|
242
|
+
expect(geometry.nav.height).toBeLessThanOrEqual(designNavContentHeight + geometry.safeBottom + 2);
|
|
243
|
+
const lastItemBottom = Math.max(...geometry.items.map(item => item.bottom));
|
|
244
|
+
expect(geometry.nav.bottom - lastItemBottom)
|
|
245
|
+
.toBeLessThanOrEqual(geometry.safeBottom + designNavInnerBottomGap + 2);
|
|
246
|
+
await page.screenshot({ path: screenshotPath, fullPage: false });
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
`safeBottom` 在此示例是 CSS 计算结果,不代表系统安全区来源已经可信。测试仍须核对运行时安全值、同一个值的唯一消费位置和桌面为零;不能用一个错误的巨大 padding 放宽几何门禁。短内容允许正文留白,禁止的是**导航下方**无业务依据的大块剩余区域。
|
|
250
|
+
|
|
251
|
+
| 场景 | 必须断言 |
|
|
252
|
+
|---|---|
|
|
253
|
+
| 三个主 Tab、短内容/空态 | 导航底边贴内屏,内栏高度有界,图标文字可见且触摸区可点 |
|
|
254
|
+
| 长内容滚动中/到底、切回 Tab | 导航位置不漂移,最后一项可达且未遮挡,壳外根滚动不变化 |
|
|
255
|
+
| 桌面 1024×600 / 1366×768 / 1920×1080 / 4K | 内屏在视口内,导航贴壳底;rpx 不随外窗放大,正文只有一个 owner |
|
|
256
|
+
| 手机 375×812 / 430×932、767/768 断点、横屏与旋转 | 移动模式去壳,内屏铺满可见区域;旋转后重测安全区和底边 |
|
|
257
|
+
| 键盘打开/关闭、浏览器栏展开/收起 | 焦点与操作可见,关闭后恢复底边,无残留占位或第二条滚动条 |
|
|
258
|
+
|
|
259
|
+
H5 键盘可能改变 visual viewport 而不改变 layout viewport;`100dvh` 不是所有键盘模式的保证。共享壳按目标浏览器处理 `visualViewport` 尺寸/偏移与 resize/恢复,原生端按配置的键盘模式测量;真机 iOS/Android 另验。缩小 Playwright 视口只证明 resize 分支,不等于软键盘实测。参考 [W3C Viewport 交互部件规则](https://www.w3.org/TR/css-viewport-1/#interactive-widget-section)。
|
|
260
|
+
|
|
261
|
+
<!-- /microi-progressive:chunk -->
|