338 lines
12 KiB
Markdown
338 lines
12 KiB
Markdown
# H5 → 微信小程序迁移:实战全路径方法论
|
||
|
||
> 基于 board-finance 等 7 个页面的实际迁移经验总结。
|
||
> 本文档是 `migration-guide.md`(理论流水线)的实战补充,聚焦工具链和操作细节。
|
||
> 更新日期:2026-03-08
|
||
|
||
---
|
||
|
||
## 一、全路径概览
|
||
|
||
```
|
||
H5 原型 HTML/CSS
|
||
│
|
||
▼
|
||
┌──────────────────────────────────────────────────────┐
|
||
│ Phase 1: 结构转换(wxml + ts + wxss 三件套) │
|
||
│ 输入: H5 源码 + 交互说明 + design-tokens │
|
||
│ 规则: 标签映射 + 87.5% 缩放 + 事件转换 │
|
||
└──────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌──────────────────────────────────────────────────────┐
|
||
│ Phase 2: 编译验证(getDiagnostics + IDE 检查) │
|
||
│ 消除 TS 类型错误、wxss 语法警告 │
|
||
└──────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌──────────────────────────────────────────────────────┐
|
||
│ Phase 3: 像素级视觉对比(自动化工具链) │
|
||
│ H5 截图 ←→ 小程序截图 → diff → 定点修复 → 循环 │
|
||
└──────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌──────────────────────────────────────────────────────┐
|
||
│ Phase 4: 交互态验证(3 种交互态截图对比) │
|
||
│ filter-dropdown / tip-modal / toc-panel 等 │
|
||
└──────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌──────────────────────────────────────────────────────┐
|
||
│ Phase 5: 收尾(tracker 更新 + dev-tools 状态同步) │
|
||
└──────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 二、Phase 1: 结构转换
|
||
|
||
### 2.1 输入物
|
||
|
||
| 材料 | 路径 | 说明 |
|
||
|------|------|------|
|
||
| H5 源码 | `docs/h5_ui/pages/<page>.html` | 结构与样式唯一真相 |
|
||
| 交互说明 | `docs/h5_ui/interactions/<page>.md` | 状态变量、事件响应 |
|
||
| Design Tokens | `docs/h5_ui/design-tokens.json` | 颜色、间距、字号 |
|
||
| 共享组件规范 | `apps/miniprogram/doc/shared-component-specs.md` | filter-dropdown 等 |
|
||
| 避坑文档 | `apps/miniprogram/doc/h5-to-miniprogram-pitfalls.md` | 22+ 个已知坑点 |
|
||
|
||
### 2.2 核心缩放公式
|
||
|
||
```
|
||
最终 rpx = H5 px × 2 × 0.875
|
||
```
|
||
|
||
- 结果取偶数(向最近偶数取整)
|
||
- 来源:iPhone 15 Pro Max 430px 宽 → 小程序 750rpx 基准,87.5% = 750/430/2
|
||
- 示例:`16px → 16 × 2 × 0.875 = 28rpx`,`12px → 12 × 2 × 0.875 = 21 → 22rpx`
|
||
|
||
### 2.3 标签映射速查
|
||
|
||
| H5 | 小程序 | 注意 |
|
||
|----|--------|------|
|
||
| `<div>` | `<view>` | |
|
||
| `<span>` | `<text>` | 小程序 text 不支持嵌套 view |
|
||
| `<img>` | `<image>` | 必须设 mode,默认 scaleToFill |
|
||
| `<a>` | `<navigator>` 或 `bindtap` | 小程序无超链接 |
|
||
| `<input>` | `<input>` 或 `<t-input>` | TDesign 优先 |
|
||
| `<button>` | `<t-button>` | TDesign 优先 |
|
||
| `<select>` | `<t-picker>` | 无原生 select |
|
||
| `<svg>` | `<t-icon>` 或 `<image>` | 小程序不支持内联 SVG |
|
||
| `<section>` | `<view>` | 语义标签统一用 view |
|
||
| `scroll 容器` | `<scroll-view>` | 必须设固定高度 |
|
||
|
||
### 2.4 样式转换要点
|
||
|
||
- Tailwind class → 手写 wxss(小程序不支持 Tailwind)
|
||
- `vh/vw` → `rpx` 或 `calc()`
|
||
- `position: fixed` → 正常工作,但注意安全区 `env(safe-area-inset-bottom)`
|
||
- `backdrop-filter` → 小程序不支持,用纯色半透明替代
|
||
- `gap` → flexbox gap 在小程序基础库 2.30+ 支持,低版本用 margin
|
||
- CSS 变量 `var(--xxx)` → 小程序不支持,直接写值
|
||
- `::before/::after` → 支持,但不能用 `content: attr()`
|
||
- 渐变 → `linear-gradient` 支持,`radial-gradient` 部分支持
|
||
|
||
### 2.5 事件转换
|
||
|
||
| H5 | 小程序 | 说明 |
|
||
|----|--------|------|
|
||
| `onclick` | `bindtap` | |
|
||
| `onchange` | `bind:change` | TDesign 组件用 `bind:change` |
|
||
| `oninput` | `bindinput` | |
|
||
| `onscroll` | `bindscroll` | 在 scroll-view 上 |
|
||
| `addEventListener` | 无 | 用 wxml 声明式绑定 |
|
||
| `e.target.dataset` | `e.currentTarget.dataset` | 注意 currentTarget |
|
||
| `e.preventDefault()` | `catchtap`(阻止冒泡) | |
|
||
|
||
|
||
---
|
||
|
||
## 三、Phase 2: 编译验证
|
||
|
||
### 3.1 TypeScript 检查
|
||
|
||
```
|
||
getDiagnostics → board-finance.ts
|
||
```
|
||
|
||
- 确保 `Page<IData>()` 类型定义完整
|
||
- data 中所有字段有初始值
|
||
- 事件处理函数签名正确(`e: WechatMiniprogram.TouchEvent`)
|
||
|
||
### 3.2 常见 TS 问题
|
||
|
||
- TDesign 组件事件类型:用 `WechatMiniprogram.CustomEvent` 而非 `TouchEvent`
|
||
- `wx:if` 条件中的变量必须在 data 中声明
|
||
- `setData` 的 key 路径必须与 data 结构一致
|
||
|
||
### 3.3 wxss 检查
|
||
|
||
微信 IDE 会报 CSS 警告(非阻塞),常见:
|
||
- 内联 style 中的空格(`style="width: 100%"` → `style="width:100%"`)
|
||
- 不支持的属性(`backdrop-filter` 等)
|
||
|
||
---
|
||
|
||
## 四、Phase 3: 像素级视觉对比(核心工具链)
|
||
|
||
这是整个迁移流程中最关键的环节。我们建立了一套完整的自动化对比工具链。
|
||
|
||
### 4.1 前置准备
|
||
|
||
#### H5 截图(一次性)
|
||
|
||
1. 用户启动 Go Live(VS Code 插件),端口 5500
|
||
2. Playwright MCP 导航到 `http://127.0.0.1:5500/docs/h5_ui/pages/<page>.html`
|
||
3. 设置视口 `430×932`(iPhone 15 Pro Max)
|
||
4. 全页面截图 → `docs/h5_ui/screenshots/<page>.png`(1290px 宽,DPR 3)
|
||
5. 交互态截图(下拉、弹窗、面板等)→ `<page>--<state>.png`
|
||
|
||
#### 微信开发者工具连接
|
||
|
||
```bash
|
||
# 用户手动启动自动化端口(或 AI 用 controlPwshProcess)
|
||
& "C:\dev\WechatDevtools\cli.bat" auto --project "C:\NeoZQYY\apps\miniprogram" --auto-port 9420
|
||
```
|
||
|
||
连接规范:
|
||
- 只能用 `wsEndpoint` 策略,`ws://127.0.0.1:9420`
|
||
- 禁止 auto/launch/connect/discover 策略
|
||
- 导航到 tabbar 页面必须用 `relaunch`,路径前加 `/`
|
||
|
||
### 4.2 对比流程(每轮迭代)
|
||
|
||
```
|
||
Step 1: 截图
|
||
mcp_weixin_devtools_mcp_relaunch → /pages/<page>/<page>
|
||
mcp_weixin_devtools_mcp_waitFor → 2000ms
|
||
mcp_weixin_devtools_mcp_screenshot → mp-<page>.png
|
||
|
||
Step 2: 尺寸统一
|
||
python scripts/ops/resize_and_compare_v2.py
|
||
→ H5 保持 1290px 宽
|
||
→ MP 截图 ×2 缩放到 1290px
|
||
→ H5 裁剪到 MP 逻辑高度对应的物理高度
|
||
→ 输出 cmp-h5.png + cmp-mp.png(同尺寸)
|
||
|
||
Step 3: 像素对比
|
||
mcp_image_compare_compare_images
|
||
→ image1: cmp-h5.png
|
||
→ image2: cmp-mp.png
|
||
→ threshold: 0.1
|
||
→ 输出 diff 图 + 差异百分比
|
||
|
||
Step 4: 差异分析
|
||
python scripts/ops/analyze_diff.py
|
||
→ 按 150px 条带分析差异密度
|
||
→ 定位差异最大的 5 个区域
|
||
|
||
Step 5: 精确位置对比
|
||
mcp_weixin_devtools_mcp_get_page_snapshot(MP 元素位置)
|
||
Playwright browser_evaluate(H5 元素位置)
|
||
→ 逐元素对比 Y 坐标和高度
|
||
|
||
Step 6: wxss 微调
|
||
根据位置差异调整 padding/margin/gap
|
||
→ 回到 Step 1 循环
|
||
```
|
||
|
||
### 4.3 DPR 换算关系
|
||
|
||
| 平台 | 物理宽度 | DPR | 逻辑宽度 |
|
||
|------|---------|-----|---------|
|
||
| H5 截图 | 1290px | 3 | 430px |
|
||
| MP 截图 | 645px | 1.5 | 430px |
|
||
|
||
统一对比宽度:1290px(MP ×2 缩放)
|
||
|
||
高度对齐:
|
||
- MP 逻辑高度 = MP 物理高度 / 1.5
|
||
- H5 裁剪高度 = MP 逻辑高度 × 3
|
||
|
||
### 4.4 差异阈值参考
|
||
|
||
| 差异% | 评价 | 行动 |
|
||
|-------|------|------|
|
||
| < 5% | 优秀 | 字体渲染级差异,可接受 |
|
||
| 5-10% | 良好 | 检查是否有结构性差异(底部内容不同) |
|
||
| 10-15% | 需调整 | 定位差异区域,微调间距 |
|
||
| > 15% | 较大 | 可能有布局错误,需逐元素排查 |
|
||
|
||
注意:底部区域(MP 只截一屏)的差异是结构性的,不算样式问题。评估时应关注前半屏的差异。
|
||
|
||
### 4.5 工具脚本
|
||
|
||
| 脚本 | 路径 | 功能 |
|
||
|------|------|------|
|
||
| resize_and_compare_v2.py | `scripts/ops/` | 统一尺寸 + 裁剪 |
|
||
| analyze_diff.py | `scripts/ops/` | 按条带分析差异分布 |
|
||
|
||
### 4.6 实战数据(board-finance)
|
||
|
||
| 轮次 | 差异% | 主要调整 |
|
||
|------|-------|---------|
|
||
| 初始 | 15.29% | 首次截图对比 |
|
||
| 第一轮 | 12.56% | 10 处间距微调(padding/margin/gap) |
|
||
| 第二轮 | 9.04% | 2 处调整(header→sub-label 间距、divider 非对称 margin) |
|
||
|
||
前半屏(Y<450px)最终差异约 3.5%,达到字体渲染级别。
|
||
|
||
---
|
||
|
||
## 五、Phase 4: 交互态验证
|
||
|
||
### 5.1 常见交互态
|
||
|
||
| 交互态 | 触发方式 | 截图命名 |
|
||
|--------|---------|---------|
|
||
| 筛选下拉 | 点击 filter-dropdown | `<page>--filter-dropdown.png` |
|
||
| 指标弹窗 | 点击 help-icon | `<page>--tip-modal.png` |
|
||
| 目录导航 | 点击 toc-btn | `<page>--toc-panel.png` |
|
||
|
||
### 5.2 小程序交互态截图方法
|
||
|
||
```
|
||
# 打开 toc-panel
|
||
mcp_weixin_devtools_mcp_click → uid=view.toc-btn
|
||
mcp_weixin_devtools_mcp_waitFor → 500ms
|
||
mcp_weixin_devtools_mcp_screenshot → mp-<page>--toc-panel.png
|
||
|
||
# 关闭(通过 evaluate_script 或点击 overlay)
|
||
mcp_weixin_devtools_mcp_evaluate_script → page.setData({ tocVisible: false })
|
||
|
||
# 打开 tip-modal
|
||
mcp_weixin_devtools_mcp_click → uid=view.help-icon-light
|
||
mcp_weixin_devtools_mcp_waitFor → 500ms
|
||
mcp_weixin_devtools_mcp_screenshot → mp-<page>--tip-modal.png
|
||
```
|
||
|
||
### 5.3 交互态对比
|
||
|
||
交互态的对比更多是视觉检查(弹窗位置、遮罩透明度、动画效果),不需要像默认态那样精确到像素。重点关注:
|
||
- 弹窗/面板的圆角、阴影、背景色
|
||
- 遮罩层透明度
|
||
- 列表项的间距和对齐
|
||
- 关闭按钮的位置
|
||
|
||
---
|
||
|
||
## 六、Phase 5: 收尾
|
||
|
||
### 6.1 更新 migration-tracker.md
|
||
|
||
- 将页面从"正在迁移"移到"已完成"
|
||
- 记录最终差异百分比和关键调整
|
||
|
||
### 6.2 更新 dev-tools 页面
|
||
|
||
- `dev-tools.ts` 中将页面从 `MIGRATING_PAGES` 移到 `DONE_PAGES`
|
||
|
||
### 6.3 截图归档
|
||
|
||
所有截图保存在 `docs/h5_ui/screenshots/`:
|
||
- `<page>.png` — H5 默认态
|
||
- `<page>--<state>.png` — H5 交互态
|
||
- `mp-<page>.png` — 小程序默认态
|
||
- `mp-<page>--<state>.png` — 小程序交互态
|
||
- `diff-<page>-v2.png` — 最终 diff 图
|
||
- `cmp-h5.png` / `cmp-mp.png` — 对比用中间文件
|
||
|
||
---
|
||
|
||
## 七、经验教训
|
||
|
||
### 7.1 高频坑点(详见 h5-to-miniprogram-pitfalls.md)
|
||
|
||
1. `scroll-view` 必须设固定高度,否则不滚动
|
||
2. `wx:if` vs `hidden`:频繁切换用 hidden,否则用 wx:if
|
||
3. 小程序 text 组件不支持嵌套 view
|
||
4. CSS `gap` 需要基础库 2.30+
|
||
5. 内联 style 中的空格会触发 IDE 警告
|
||
6. tabbar 页面只能用 `switchTab` 或 `reLaunch` 导航
|
||
|
||
### 7.2 效率提升点
|
||
|
||
- 先完成整体结构转换,再做像素级微调(不要边转边调)
|
||
- 用 `get_page_snapshot` 获取精确元素位置,比目测高效 10 倍
|
||
- `evaluate_script` 可以直接操作页面 data,比 UI 操作更可靠
|
||
- 每轮微调控制在 2-5 处修改,避免一次改太多难以定位效果
|
||
|
||
### 7.3 差异收敛规律
|
||
|
||
- 第一轮调整通常能降 3-5 个百分点(修复明显的间距错误)
|
||
- 第二轮再降 2-3 个百分点(精细间距对齐)
|
||
- 低于 10% 后继续调整收益递减(剩余差异多为字体渲染和平台差异)
|
||
- 前半屏 < 5% 即可视为达标
|
||
|
||
---
|
||
|
||
## 八、文档索引
|
||
|
||
| 文档 | 路径 | 内容 |
|
||
|------|------|------|
|
||
| 迁移指南(理论) | `apps/miniprogram/doc/migration-guide.md` | 6 步流水线 |
|
||
| 本文档(实战) | `apps/miniprogram/doc/migration-method-full-path.md` | 工具链全路径 |
|
||
| 避坑文档 | `apps/miniprogram/doc/h5-to-miniprogram-pitfalls.md` | 22+ 个坑点 |
|
||
| 共享组件规范 | `apps/miniprogram/doc/shared-component-specs.md` | 组件接口定义 |
|
||
| 迁移追踪 | `apps/miniprogram/doc/migration-tracker.md` | 页面进度 |
|