12 KiB
12 KiB
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 截图(一次性)
- 用户启动 Go Live(VS Code 插件),端口 5500
- Playwright MCP 导航到
http://127.0.0.1:5500/docs/h5_ui/pages/<page>.html - 设置视口
430×932(iPhone 15 Pro Max) - 全页面截图 →
docs/h5_ui/screenshots/<page>.png(1290px 宽,DPR 3) - 交互态截图(下拉、弹窗、面板等)→
<page>--<state>.png
微信开发者工具连接
# 用户手动启动自动化端口(或 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)
scroll-view必须设固定高度,否则不滚动wx:ifvshidden:频繁切换用 hidden,否则用 wx:if- 小程序 text 组件不支持嵌套 view
- CSS
gap需要基础库 2.30+ - 内联 style 中的空格会触发 IDE 警告
- 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 |
页面进度 |