34 KiB
H5 原型 → 微信小程序迁移桥接规范(主规范 v3.0)
版本:v3.0
适用对象:人工开发、AI 批量迁移、代码审查、验收回归
适用范围:本项目docs/h5_ui/原型页面到微信原生小程序的迁移
目标:实现页面与交互的高还原迁移,样式、层级、动效、状态切换、页面流转 1:1 对齐 H5 验收原型
📖 文档使用指南
本文档定位
这是执行规程,不是知识笔记。使用本规范时,AI 或开发者必须做到:
- 能从单个 H5 页面产出对应的小程序页面文件
- 能明确哪些能力可直接迁移,哪些必须降级,哪些禁止直迁
- 能在不使用 DOM API 的前提下,把 H5 交互改造成小程序的数据驱动实现
- 能输出可交付物,而不是停留在"分析建议"
文档结构
- 第一部分(§1-4):执行规程 - 输入输出、强制决策、能力分级
- 第二部分(§5-9):技术换算 - 尺寸、字号、颜色、布局、装饰
- 第三部分(§10-12):交互改造 - WXML 映射、数据驱动、API 替换
- 第四部分(§13):执行流程 - 10 步标准流程
- 附录引用(§14):4 个附录字典的索引
配套文档
- 附录 A:Spacing 与尺寸字典
- 附录 B:字体与文本字典(v3.1,含 line-height 规则)
- 附录 C:颜色字典
- 附录 D:布局类映射字典
- 附录索引:
docs/miniprogram-dev/New/h5_to_wechat_miniprogram_migration_bridge_appendix_index_v3.md
第一部分:执行规程
1. 输入输出契约
1.1 输入物
单页迁移时,输入物必须至少包含:
- 对应 H5 页面 HTML 文件
- 该页面引用的 CSS(页面内
<style>、独立 css 文件、Tailwind utility) - 该页面引用的 JS
- 该页面依赖的图片 / 图标 / SVG / JSON Mock
- 页面跳转关系和入口参数
1.2 输出物
每个页面迁移后,必须至少产出:
pages/<route>/<route>.wxmlpages/<route>/<route>.wxsspages/<route>/<route>.jspages/<route>/<route>.json- 该页面使用到的 mock 数据文件或页面内 mock 常量
- 迁移说明(至少包含:状态变量、事件、待确认项、降级项)
1.3 不允许的输出
以下结果视为未完成:
- 只给"迁移思路",不产出页面文件
- 只把 Tailwind class 翻译成 CSS,不改 WXML / 交互
- 继续依赖
document.*、window.*、history.*、localStorage等浏览器 API - 以"兼容性未知"为由保留 H5 写法不处理
- 把高风险 CSS 特性原样搬过去,且不写降级方案
2. 项目级强制决策
2.1 框架与运行时
- 必须使用微信原生小程序页面体系:WXML + WXSS + JS + JSON
- 禁止继续在小程序端运行 Tailwind CDN / 浏览器脚本
- 禁止使用 DOM 驱动交互,页面必须改为数据驱动
- 不引入 Taro / uni-app / WebView 兜底,本规范面向原生小程序页面迁移
2.2 验收基准
- H5 原型的主要验收基准宽度为 412 CSS px
- 小程序以 412 宽设备的视觉效果为主验收目标
- 其他常见宽度设备允许比例差异,但不得出现:文本溢出、遮挡、错层、关键按钮点击区域异常、吸顶/弹层错位
2.3 单位策略
采用 rpx 为主、px 为辅 的混合单位方案。
优先 rpx:
- 页面宽度、横向布局、卡片尺寸
- 主容器 padding / margin、列表间距、栅格
- 吸顶区高度、块级间距
优先 px:
- 1px 发丝线、阴影 blur/spread
- 小图标、绝对定位微调、小控件尺寸
- 状态栏 / 安全区补偿、细描边
按效果决定:
- 字号、圆角、局部 padding、某些 transform 位移
换算基准:
rpx = H5_CSS_px × (750 / 412)
≈ H5_CSS_px × 1.8204
取整规则:
- 普通布局值:四舍五入到整数 rpx
- 高频 token:沉淀成统一变量表(见附录 A),保持全项目一致
- 视觉敏感值:以真机截图比对微调,不强行套公式
2.4 页面滚动策略
- 默认使用 页面自然滚动
- 只有在必须做局部滚动区域时,才使用
scroll-view - 吸顶、滚动联动、section 感知优先围绕页面滚动实现;不要无必要把整页包进
scroll-view
2.5 样式组织策略
- 全局 token、复用组件样式放
app.wxss或公共样式文件 - 页面私有样式放页面同名
.wxss - 样式优先使用 class,动态值用内联 style 绑定
- 不以 CSS 变量作为唯一运行前提;优先输出静态色值 / 静态 token
2.6 文本与行高策略 ⚠️
关键发现:微信小程序的 <text> 组件不能直接设置 line-height,必须通过外层 <view> 设置。
全局设置(推荐):
page {
line-height: 1.5; /* Tailwind 默认行高 */
}
view {
line-height: inherit; /* view 继承 page 的 line-height */
}
/* text 会自动继承外层 view 的 line-height,不需要额外设置 */
局部覆盖:
.section-title {
font-size: 26rpx;
line-height: 36rpx; /* 在 view 的 class 上设置,text 会继承 */
font-weight: 600;
}
<view class="section-title">
<text>标题文本</text>
</view>
错误做法:
/* ❌ 直接在 text 上设置 line-height 无效 */
text {
line-height: 36rpx; /* 不会生效 */
}
执行规则:
- 所有文本类样式必须同时设置
font-size和line-height line-height必须在外层<view>的 class 上设置,不能在<text>上设置- 标准字号的
line-height换算参考附录 B.3 - 若发现 Y 轴高度与 H5 端不一致,优先检查
line-height是否正确设置
2.7 SVG / 图标策略
- 禁止把 H5 的内联
<svg>...</svg>直接当 WXML DOM 搬运 - 资源层允许
svg文件进入小程序项目包,但页面显示是否稳定,必须以目标设备实测为准 - 默认执行顺序:
- 简单静态图标:优先导出为独立资源文件
- 若
svg渲染不稳定:转为png - 高频单色图标:允许改为 iconfont / 组件化图标
- 动态换色的 SVG 不要临时拼接字符串;应改为多份资源、图标组件或样式控制的等价实现
3. 能力分级(A/B/C 类)
3.1 A 类:可直接使用
以下能力在当前项目中视为稳定迁移能力:
app.wxss/ 页面wxss/@importrpx.class、#id、元素选择器、::before、::afterflex、position: relative/absolute/fixedbox-shadow、border-radius、linear-gradientopacity、常规transformtransition、animation- 动态内联样式绑定
onPageScrollwx.createAnimation()wx.createSelectorQuery()wx.createIntersectionObserver()navigator/wx.navigateTo/wx.redirectTo/wx.switchTab/wx.navigateBackview/navigator的hover-class
3.2 B 类:有条件使用,必须带回退或验证
以下能力允许使用,但不能把它们当成项目硬依赖:
position: stickygridfilter: blur()backdrop-filterclip-pathvhline-clamp- 复杂组合选择器
- 资源型
svg - CSS 变量
执行规则:
- 使用前必须确认该页面已有回退方案
- 若页面对视觉或交互依赖度高,则必须做真机验证
- 若 B 类能力失效,不得阻塞交付,必须切换为本规范定义的降级实现
3.3 C 类:禁止直迁
以下能力不得原样从 H5 搬到小程序:
document.getElementById/querySelector/querySelectorAllclassList.add/remove/toggle- 直接改
element.style.xxx innerHTML/textContent方式渲染视图window.scrollY/window.scrollTohistory.backlocalStorage/sessionStoragealert/confirm- CSS
env(safe-area-inset-*) :hover/group-hover:*- 依赖浏览器焦点模型的
:focus/:active交互 - 依赖
:first-child/:last-child/:nth-child才能成立的视觉规则
4. Tailwind CSS 在本项目中的行为
4.1 Tailwind CSS 渲染机制
本项目 H5 原型使用 <script src="https://cdn.tailwindcss.com"></script>(Tailwind CSS v3 CDN Play 模式)。
Tailwind v3 默认主题中,大量 spacing、font-size、border-radius token 主要使用 rem 体系。在浏览器默认根字号 1rem = 16px 且页面未主动改写 html { font-size } 的前提下,这些 rem 体系的 utility 会计算成固定 CSS px 值。
关键事实:Tailwind 默认 rem 体系的 utility class 在任何设备上都会计算为固定的 CSS px 值,与设备布局宽度无关。
4.2 微信 rpx 的精确定义
来源:微信官方 WXSS 文档
rpx(responsive pixel):可以根据屏幕宽度进行自适应。规定屏幕宽为 750rpx。
换算公式:
1rpx = 屏幕宽度px / 750
1px = 750 / 屏幕宽度px × rpx
官方示例:
| 设备 | 屏幕宽度 | 1rpx = ?px | 1px = ?rpx |
|---|---|---|---|
| iPhone 5 | 320px | 0.42px | 2.34rpx |
| iPhone 6 | 375px | 0.5px | 2rpx |
| iPhone 6 Plus | 414px | 0.552px | 1.81rpx |
4.3 本项目的换算链路
验收基准设备:等效宽度 412px
完整链路:Tailwind class → CSS 计算值(px) → rpx
rpx = CSS_px × (750 / 412)
= CSS_px × 1.82039...
(待续:第二部分将包含详细的技术换算表)
📚 快速导航
- 执行规程:§1-4(当前部分)
- 技术换算:§5-9(见下文)
- 交互改造:§10-12(见下文)
- 执行流程:§13(见下文)
- 附录索引:§14(见下文)
版本历史
- v3.0(2026-03-14):合并 v1.0 技术换算基础和 v2.0 执行规范,补充 line-height 关键发现
- v2.0:执行规范,强化输入输出契约和能力分级
- v1.0:技术换算基础,建立完整的映射表
H5 原型 → 微信小程序迁移桥接规范(主规范 v3.0 - 第二部分)
接续第一部分,本部分包含:§5-9 技术换算基础
第二部分:技术换算基础
5. Tailwind Spacing → rpx 完整换算表
Tailwind v3 的 spacing scale 基于 0.25rem = 4px 步进。以下是本项目原型中实际使用的所有 spacing 值的精确换算。这些 rpx 值已在已迁移页面中使用,作为项目统一 token,后续页面应保持一致。
5.1 Tailwind spacing scale(默认)
| Tailwind 值 | rem | CSS px | rpx(项目 token) | 常见用途 |
|---|---|---|---|---|
0.5 |
0.125rem | 2px | 4rpx | gap-0.5, p-0.5, mt-0.5 |
px |
1px | 1px | 2rpx | py-px, w-px |
1 |
0.25rem | 4px | 8rpx | gap-1, p-1, mt-1, mb-1 |
1.5 |
0.375rem | 6px | 12rpx | gap-1.5, p-1.5, mt-1.5 |
2 |
0.5rem | 8px | 14rpx | gap-2, p-2, mt-2, mb-2 |
2.5 |
0.625rem | 10px | 18rpx | gap-2.5, p-2.5, mb-2.5 |
3 |
0.75rem | 12px | 22rpx | gap-3, p-3, mb-3, pl-3 |
3.5 |
0.875rem | 14px | 26rpx | p-3.5, h-3.5, w-3.5 |
4 |
1rem | 16px | 30rpx | gap-4, p-4, px-4, mb-4 |
5 |
1.25rem | 20px | 36rpx | p-5, px-5, mb-5, pb-5 |
6 |
1.5rem | 24px | 44rpx | gap-6, p-6, px-6, mb-6 |
7 |
1.75rem | 28px | 52rpx | h-7, w-7 |
8 |
2rem | 32px | 58rpx | px-8, mb-8, pb-8, h-8 |
10 |
2.5rem | 40px | 72rpx | h-10, w-10, pb-10 |
12 |
3rem | 48px | 88rpx | h-12, w-12, pb-12 |
16 |
4rem | 64px | 116rpx | h-16, w-16 |
20 |
5rem | 80px | 146rpx | h-20, w-20, top-20 |
24 |
6rem | 96px | 174rpx | h-24, w-24 |
32 |
8rem | 128px | 232rpx | h-32, w-32 |
40 |
10rem | 160px | 292rpx | bottom-40, top-40 |
详细完整表格:参见附录 A
6. Tailwind 字号 → WXSS font-size + line-height 完整换算表
6.1 核心规则
Tailwind v3 的字号类(text-xs、text-sm 等)同时设置 font-size 和 line-height。
例如 text-sm 生成的 CSS 是:
font-size: 0.875rem; /* 14px */
line-height: 1.25rem; /* 20px */
强制规则:每个 Tailwind 字号类转 WXSS 时,必须同时写 font-size 和 line-height。
6.2 微信小程序 text 组件的 line-height 限制 ⚠️
关键发现:微信小程序的 <text> 组件不能直接设置 line-height,必须通过外层 <view> 设置。
正确做法:参见 §2.6
原因:微信小程序的 <text> 是特殊的内联组件,直接设置 line-height 不生效,必须在外层 <view> 上设置。
验证方法:在开发者工具的 Computed 面板中,text 元素不会显示 line-height 属性,但外层 view 的 height 值会包含行高效果。
6.3 标准字号类换算表
| Tailwind class | font-size (px) | line-height (px) | WXSS font-size | WXSS line-height |
|---|---|---|---|---|
text-xs |
12px | 16px | 22rpx | 29rpx |
text-sm |
14px | 20px | 26rpx | 36rpx |
text-base |
16px | 24px | 30rpx | 44rpx |
text-lg |
18px | 28px | 33rpx | 51rpx |
text-xl |
20px | 28px | 36rpx | 51rpx |
text-2xl |
24px | 32px | 44rpx | 58rpx |
text-3xl |
30px | 36px | 54rpx | 66rpx |
换算公式:
font-size(rpx) = font-size(px) × 1.8204
line-height(rpx) = line-height(px) × 1.8204
详细完整表格:参见附录 B
6.4 font-weight 映射
| Tailwind class | CSS font-weight | WXSS |
|---|---|---|
font-normal |
400 | font-weight: 400 |
font-medium |
500 | font-weight: 500 |
font-semibold |
600 | font-weight: 600 |
font-bold |
700 | font-weight: 700 |
注意:font-medium 是 500 不是 600。这是常见错误。
6.5 其他文本属性
| Tailwind class | WXSS |
|---|---|
text-center |
text-align: center |
text-right |
text-align: right |
text-left |
text-align: left |
truncate |
overflow: hidden; text-overflow: ellipsis; white-space: nowrap |
line-clamp-2 |
display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden |
whitespace-nowrap |
white-space: nowrap |
underline |
text-decoration: underline |
line-through |
text-decoration: line-through |
7. Tailwind 颜色 → WXSS 颜色完整映射
7.1 项目自定义颜色
每个 HTML 页面的 <script> 中定义了相同的自定义颜色扩展:
| Tailwind 名称 | 色值 | WXSS 变量 |
|---|---|---|
primary |
#0052d9 |
var(--color-primary) |
primary-light |
#ecf2fe |
var(--color-primary-light) |
success |
#00a870 |
var(--color-success) |
warning |
#ed7b2f |
var(--color-warning) |
error |
#e34d59 |
var(--color-error) |
gray-1 |
#f3f3f3 |
var(--color-gray-1) |
gray-7 |
#8b8b8b |
var(--color-gray-7) |
gray-9 |
#5e5e5e |
var(--color-gray-9) |
gray-13 |
#242424 |
var(--color-gray-13) |
详细完整表格:参见附录 C
7.2 透明度变体
原型大量使用 Tailwind 的透明度修饰符(/N),如 bg-primary/10、text-white/60。
WXSS 映射方式:使用 rgba() 或直接写带透明度的色值。
| 透明度后缀 | alpha 值 | 示例 |
|---|---|---|
/10 |
0.10 | bg-primary/10 → rgba(0, 82, 217, 0.10) |
/20 |
0.20 | bg-white/20 → rgba(255, 255, 255, 0.20) |
/50 |
0.50 | bg-black/50 → rgba(0, 0, 0, 0.50) |
/80 |
0.80 | bg-white/80 → rgba(255, 255, 255, 0.80) |
8. Tailwind 布局类 → WXSS 完整映射
8.1 Flexbox
| Tailwind class | CSS | WXSS |
|---|---|---|
flex |
display: flex |
display: flex |
flex-col |
flex-direction: column |
flex-direction: column |
flex-1 |
flex: 1 1 0% |
flex: 1 |
flex-shrink-0 |
flex-shrink: 0 |
flex-shrink: 0 |
flex-wrap |
flex-wrap: wrap |
flex-wrap: wrap |
items-center |
align-items: center |
align-items: center |
items-start |
align-items: flex-start |
align-items: flex-start |
justify-between |
justify-content: space-between |
justify-content: space-between |
justify-center |
justify-content: center |
justify-content: center |
8.2 Grid
| Tailwind class | CSS | WXSS |
|---|---|---|
grid |
display: grid |
display: grid |
grid-cols-2 |
grid-template-columns: repeat(2, minmax(0, 1fr)) |
grid-template-columns: repeat(2, minmax(0, 1fr)) |
grid-cols-3 |
grid-template-columns: repeat(3, minmax(0, 1fr)) |
grid-template-columns: repeat(3, minmax(0, 1fr)) |
grid-cols-4 |
grid-template-columns: repeat(4, minmax(0, 1fr)) |
grid-template-columns: repeat(4, minmax(0, 1fr)) |
8.3 Gap(间距)
| Tailwind class | CSS | WXSS |
|---|---|---|
gap-1 |
gap: 4px |
gap: 8rpx |
gap-2 |
gap: 8px |
gap: 14rpx |
gap-3 |
gap: 12px |
gap: 22rpx |
gap-4 |
gap: 16px |
gap: 30rpx |
gap-x-3 |
column-gap: 12px |
column-gap: 22rpx |
gap-y-2 |
row-gap: 8px |
row-gap: 14rpx |
8.4 定位
| Tailwind class | CSS | WXSS |
|---|---|---|
relative |
position: relative |
position: relative |
absolute |
position: absolute |
position: absolute |
fixed |
position: fixed |
position: fixed |
sticky |
position: sticky |
见 §3.2 兼容性说明 |
inset-0 |
inset: 0 |
top: 0; right: 0; bottom: 0; left: 0 |
top-0 |
top: 0 |
top: 0 |
z-10 |
z-index: 10 |
z-index: 10 |
z-50 |
z-index: 50 |
z-index: 50 |
8.5 尺寸
| Tailwind class | CSS | WXSS |
|---|---|---|
w-full |
width: 100% |
width: 100% |
h-full |
height: 100% |
height: 100% |
w-1/2 |
width: 50% |
width: 50% |
min-h-screen |
min-height: 100vh |
min-height: 100vh |
详细完整表格:参见附录 D
9. Tailwind 装饰类 → WXSS 完整映射
9.1 圆角
| Tailwind class | CSS | WXSS |
|---|---|---|
rounded |
border-radius: 4px |
border-radius: 8rpx |
rounded-lg |
border-radius: 8px |
border-radius: 14rpx |
rounded-xl |
border-radius: 12px |
border-radius: 22rpx |
rounded-2xl |
border-radius: 16px |
border-radius: 30rpx |
rounded-full |
border-radius: 9999px |
border-radius: 50% 或 border-radius: 999rpx |
9.2 阴影
| Tailwind class | CSS | WXSS |
|---|---|---|
shadow-sm |
box-shadow: 0 1px 2px 0 rgba(0,0,0,0.05) |
box-shadow: 0 2rpx 4rpx 0 rgba(0,0,0,0.05) |
shadow-lg |
box-shadow: 0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -4px rgba(0,0,0,0.1) |
box-shadow: 0 18rpx 28rpx -6rpx rgba(0,0,0,0.1), 0 8rpx 12rpx -8rpx rgba(0,0,0,0.1) |
9.3 边框
| Tailwind class | CSS | WXSS |
|---|---|---|
border |
border: 1px solid |
border: 1px solid |
border-2 |
border: 2px solid |
border: 2px solid |
border-b |
border-bottom: 1px solid |
border-bottom: 1px solid |
border-t |
border-top: 1px solid |
border-top: 1px solid |
9.4 渐变
| Tailwind class | CSS | WXSS |
|---|---|---|
bg-gradient-to-r |
background-image: linear-gradient(to right, ...) |
background: linear-gradient(to right, ...) |
bg-gradient-to-br |
background-image: linear-gradient(to bottom right, ...) |
background: linear-gradient(to bottom right, ...) |
from-X |
渐变起始色 | 渐变第一个色值 |
to-X |
渐变结束色 | 渐变最后一个色值 |
示例:bg-gradient-to-br from-blue-400 to-blue-500
→ WXSS: background: linear-gradient(to bottom right, #60a5fa, #3b82f6)
9.5 透明度与模糊
| Tailwind class | CSS | WXSS | 小程序兼容性 |
|---|---|---|---|
opacity-30 |
opacity: 0.3 |
opacity: 0.3 |
✓ |
opacity-60 |
opacity: 0.6 |
opacity: 0.6 |
✓ |
backdrop-blur-md |
backdrop-filter: blur(12px) |
见 §3.2 | ⚠️ 部分支持 |
blur-xl |
filter: blur(24px) |
filter: blur(24px) |
✓ |
(待续:第三部分将包含交互改造)
📚 快速导航
- 执行规程:§1-4(见第一部分)
- 技术换算:§5-9(当前部分)
- 交互改造:§10-12(见第三部分)
- 执行流程:§13(见第三部分)
- 附录索引:§14(见第三部分)
H5 原型 → 微信小程序迁移桥接规范(主规范 v3.0 - 第三部分)
接续第二部分,本部分包含:§10-12 交互改造、§13 执行流程、§14 附录索引
第三部分:交互改造
10. HTML 标签 → WXML 组件映射
10.1 基础标签映射
| H5 标签 | WXML 组件 | 说明 |
|---|---|---|
<div> |
<view> |
通用容器 |
<span> |
<text> |
行内文本。注意:<text> 内只能嵌套 <text>,不能嵌套 <view> |
<p> |
<view> 或 <text> |
段落 |
<img> |
<image> |
图片。必须指定 mode 属性 |
<a> |
<navigator> 或 <view bindtap> |
链接/跳转 |
<button> |
<button> 或 <view bindtap> |
按钮 |
<input> |
<input> |
输入框 |
<textarea> |
<textarea> |
多行输入 |
<svg> |
<image src="xxx.svg"> |
小程序不支持内联 SVG |
<ul> / <ol> / <li> |
<view> |
列表容器 |
10.2 image 组件的 mode 属性
| H5 CSS | image mode |
|---|---|
object-fit: cover |
mode="aspectFill" |
object-fit: contain |
mode="aspectFit" |
| 无特殊设置 | mode="widthFix"(宽度撑满,高度自适应) |
10.3 事件属性映射
| H5 事件 | WXML 事件 | 说明 |
|---|---|---|
onclick |
bindtap |
点击 |
onchange |
bindchange |
值变化 |
oninput |
bindinput |
输入 |
onscroll |
bindscroll(scroll-view)或 onPageScroll(页面) |
滚动 |
ontouchstart |
bindtouchstart |
触摸开始 |
ontouchend |
bindtouchend |
触摸结束 |
oncontextmenu |
bindlongpress |
长按 |
注意:
bind前缀事件会冒泡catch前缀事件会阻止冒泡(等同于e.stopPropagation())catchtouchmove:阻止触摸移动冒泡(常用于遮罩层阻止背景滚动)
11. JS DOM 操作 → 小程序数据驱动完整映射
11.1 总体原则
H5 模式:用户操作 → JS 查询 DOM → 修改 DOM 属性/样式/内容 → 视觉变化
小程序模式:用户操作 → 事件处理函数 → setData 更新数据 → WXML 自动重渲染 → 视觉变化
禁止在小程序中使用的 H5 API:
document.getElementById()document.querySelector()/querySelectorAll()element.classList.add/remove/toggle/containselement.style.xxx = yyyelement.innerHTML/textContentdocument.createElement()/appendChild()
11.2 模式 A:显示/隐藏切换
H5 写法:
document.getElementById('modal').classList.remove('hidden')
document.getElementById('modal').classList.add('flex')
小程序写法:
// JS
Page({
data: { showModal: false },
openModal() { this.setData({ showModal: true }) },
closeModal() { this.setData({ showModal: false }) }
})
<!-- WXML -->
<view wx:if="{{showModal}}" class="modal-overlay" catchtouchmove bindtap="closeModal">
<view class="modal-content" catchtap>
<!-- 弹窗内容 -->
</view>
</view>
11.3 模式 B:Tab/状态切换
H5 写法:
function switchTab(tabName) {
document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'))
document.getElementById('tab-' + tabName).classList.add('active')
}
小程序写法:
Page({
data: { activeTab: 'basic' },
onTabChange(e) {
this.setData({ activeTab: e.currentTarget.dataset.tab })
}
})
<view class="tab {{activeTab === 'basic' ? 'tab--active' : ''}}"
data-tab="basic" bindtap="onTabChange">基础课</view>
<view class="tab {{activeTab === 'vip' ? 'tab--active' : ''}}"
data-tab="vip" bindtap="onTabChange">VIP课</view>
<view wx:if="{{activeTab === 'basic'}}">基础课内容</view>
<view wx:if="{{activeTab === 'vip'}}">VIP课内容</view>
11.4 模式 C:展开/收起
H5 写法:
function toggleExpand(id) {
const el = document.getElementById(id)
el.classList.toggle('hidden')
}
小程序写法:
Page({
data: { expandedSections: {} },
toggleSection(e) {
const key = e.currentTarget.dataset.key
this.setData({ [`expandedSections.${key}`]: !this.data.expandedSections[key] })
}
})
<view bindtap="toggleSection" data-key="detail">
<text>{{expandedSections.detail ? '收起' : '展开更多'}}</text>
</view>
<view wx:if="{{expandedSections.detail}}">
<!-- 展开内容 -->
</view>
11.5 模式 D:内容动态更新
H5 写法:
document.getElementById('total').textContent = '¥12,345'
document.getElementById('list').innerHTML = items.map(i => `<div>${i.name}</div>`).join('')
小程序写法:
Page({
data: { total: '¥12,345', items: [] },
loadData() {
this.setData({
total: '¥12,345',
items: [{ name: '台桌' }, { name: '酒水' }]
})
}
})
<text>{{total}}</text>
<view wx:for="{{items}}" wx:key="name">
<text>{{item.name}}</text>
</view>
11.6 模式 E:滚动联动
H5 写法:
window.addEventListener('scroll', () => {
const currentY = window.scrollY
if (currentY > 100) {
filterBar.classList.add('filter-bar-hidden')
}
})
小程序写法:
Page({
data: { filterBarVisible: true },
_lastScrollTop: 0,
_throttleTimer: null,
onPageScroll(e) {
// 节流:避免每帧 setData
if (this._throttleTimer) return
this._throttleTimer = setTimeout(() => {
this._throttleTimer = null
}, 100)
const scrollTop = e.scrollTop
const shouldHide = scrollTop > 100
// 只在状态真正变化时 setData
if (shouldHide !== !this.data.filterBarVisible) {
this.setData({ filterBarVisible: !shouldHide })
}
}
})
关键规则:
- 滚动事件处理函数中必须做节流(100ms 以上)
- 只在状态真正变化时调用
setData,避免无意义的重渲染 - 不要在滚动事件中更新大量数据或触发复杂计算
11.7 模式 F:页面导航
H5 写法:
window.location.href = 'task-detail.html?id=123'
history.back()
小程序写法:
// 普通页面跳转
wx.navigateTo({ url: '/pages/task-detail/task-detail?id=123' })
// 返回上一页
wx.navigateBack()
// TabBar 页面跳转
wx.switchTab({ url: '/pages/task-list/task-list' })
// 重定向(替换当前页)
wx.redirectTo({ url: '/pages/login/login' })
关键规则:TabBar 页面(在 app.json 的 tabBar.list 中定义的)必须用 wx.switchTab,用 navigateTo 会静默失败。
12. 浏览器 API → 微信小程序 API 完整映射
12.1 导航
| H5 API | 小程序 API | 说明 |
|---|---|---|
window.location.href = url |
wx.navigateTo({ url }) |
普通页面跳转 |
window.location.replace(url) |
wx.redirectTo({ url }) |
替换当前页 |
history.back() |
wx.navigateBack() |
返回上一页 |
| — | wx.switchTab({ url }) |
TabBar 页面跳转(必须用这个) |
12.2 滚动
| H5 API | 小程序 API | 说明 |
|---|---|---|
window.scrollY |
onPageScroll(e) 中 e.scrollTop |
页面滚动位置 |
window.scrollTo(0, y) |
wx.pageScrollTo({ scrollTop: y }) |
滚动到指定位置 |
element.scrollIntoView() |
scroll-view 的 scroll-into-view="{{id}}" |
滚动到指定元素 |
element.getBoundingClientRect() |
wx.createSelectorQuery().select('.cls').boundingClientRect() |
获取元素位置(异步) |
12.3 存储
| H5 API | 小程序 API | 说明 |
|---|---|---|
localStorage.setItem(k, v) |
wx.setStorageSync(k, v) |
同步写入 |
localStorage.getItem(k) |
wx.getStorageSync(k) |
同步读取 |
localStorage.removeItem(k) |
wx.removeStorageSync(k) |
同步删除 |
localStorage.clear() |
wx.clearStorageSync() |
清空全部 |
12.4 剪贴板
| H5 API | 小程序 API |
|---|---|
navigator.clipboard.writeText(text) |
wx.setClipboardData({ data: text }) |
navigator.clipboard.readText() |
wx.getClipboardData() |
12.5 对话框
| H5 API | 小程序 API |
|---|---|
alert(msg) |
wx.showModal({ title: '', content: msg, showCancel: false }) |
confirm(msg) |
wx.showModal({ title: '提示', content: msg }) |
| — | wx.showToast({ title: msg, icon: 'success' }) |
12.6 系统信息
| 需求 | 小程序 API |
|---|---|
| 状态栏高度 | wx.getSystemInfoSync().statusBarHeight |
| 屏幕宽度 | wx.getSystemInfoSync().windowWidth |
| 安全区域 | wx.getSystemInfoSync().safeArea |
| 底部安全区高度 | screenHeight - safeArea.bottom |
第四部分:执行流程
13. 页面转换的标准执行流程(10 步)
每迁移 1 个页面,都必须按以下顺序执行。
步骤 1:页面资产盘点
输入:HTML / CSS / JS / 图片资源
动作:
- 抽取页面标题、路由名、入口参数、返回路径
- 列出页面块:顶部、卡片区、列表区、底部操作区、弹层、浮层、Toast
- 列出页面状态:默认态、空态、加载态、错误态、选中态、展开态、禁用态
- 列出页面动效:淡入、位移、缩放、吸顶、滚动联动、长按、评分拖动
输出:页面迁移卡
步骤 2:结构改写为 WXML 语义树
动作:
div→view- 文本优先用
text - 图片用
image - 链接/跳转用
navigator或bindtap - 表单元素替换为原生小程序组件
- 列表一律改为
wx:for - 条件显示一律改为
wx:if/hidden/ 条件 class
禁止:
- 保留 H5 DOM 层级只是把标签名替换一下
- 在
text内嵌套view - 用字符串拼接 HTML 片段
步骤 3:Tailwind 与自定义 CSS 拆解
动作:
- 先按视觉功能拆成:布局、尺寸、文本、颜色、装饰、状态、动画
- 再判断每个值使用
rpx还是px - 统一抽出公共 token,不允许每页各自发散命名
要求:
- 不保留"一长串 utility class 直接照搬"的中间态
- 对频繁出现的组合样式抽成语义类,如
.card、.section-title、.tab--active
步骤 4:交互从 DOM 驱动改为数据驱动
动作:
- 把所有 DOM 查询改成状态变量
- 把显隐、激活、展开、选中、校验、加载都改成
data驱动 - 把滚动联动改成
onPageScroll+ 节流 + 仅在状态变化时setData
输出:状态表
状态表至少包含:
- 状态变量名
- 默认值
- 可选值
- 受哪个事件修改
- 影响哪些视图
步骤 5:页面级动效实现
执行规则:
- 纯显隐 / 透明度 / 位移 / 简单位移动画:优先
transition/animation - 需要顺序编排、组合变换、受事件精确驱动:用
wx.createAnimation() - 高频交互不要每帧
setData
步骤 6:导航与参数改造
动作:
- 普通页面:
wx.navigateTo - 替换当前页:
wx.redirectTo - tabBar 页面:
wx.switchTab - 返回:
wx.navigateBack - 页面参数:统一在
onLoad(query)中读取
步骤 7:安全区与导航栏补偿
动作:
- 禁止使用
env(safe-area-inset-*) - 通过系统信息计算状态栏与底部安全区
- 自定义导航栏页面必须统一实现,不得一页一套
步骤 8:Mock 数据接入
动作:
- 页面先用 mock 跑通
- 模板静态文案与后端数据字段分开
- 所有列表、徽标、状态标签都要有 mock
步骤 9:真机回归与像素微调
动作:
- 先看 412 宽主验收设备
- 再看至少一台 375 宽设备
- 出现不对齐时优先微调局部
px/rpx,不要推翻整体单位策略
步骤 10:记录迁移说明
每页必须输出迁移说明,至少包含:
- 页面依赖资源
- 迁移状态变量
- 高风险点
- 已做降级项
14. 附录文档索引
14.1 附录清单
位于 docs/miniprogram-dev/New/:
- 附录索引:
h5_to_wechat_miniprogram_migration_bridge_appendix_index_v3.md(v3.1) - 附录 A:
appendix_a_spacing_and_sizing_dictionary_v3.md- Spacing 与尺寸字典 - 附录 B:
appendix_b_typography_and_text_dictionary_v3.md(v3.1)- 字体与文本字典 - 附录 C:
appendix_c_color_dictionary_v3.md- 颜色字典 - 附录 D:
appendix_d_layout_class_mapping_dictionary_v3.md- 布局类映射字典
14.2 使用方式
AI 使用顺序:
- 加载本主规范(v3.0)
- 加载附录索引
- 按需加载具体附录(A/B/C/D)
- 执行迁移
开发者使用顺序:
- 先读本主规范了解整体流程和规则
- 迁移时查阅附录进行 token 映射
- 遇到问题时回到主规范查找解决方案
14.3 附录更新记录
- v3.1(2026-03-14):附录 B 补充 text 组件的 line-height 设置规则
- v3.0:初始版本,建立附录索引和四个附录字典
📚 完整导航
-
第一部分:执行规程(§1-4)
- 输入输出契约
- 项目级强制决策
- 能力分级(A/B/C 类)
- Tailwind CSS 行为说明
-
第二部分:技术换算(§5-9)
- Spacing 换算表
- 字号与行高换算
- 颜色映射
- 布局类映射
- 装饰类映射
-
第三部分:交互改造(§10-12)
- HTML→WXML 映射
- DOM 操作→数据驱动
- 浏览器 API→小程序 API
-
第四部分:执行流程(§13-14)
- 10 步标准流程
- 附录文档索引
版本历史
- v3.0(2026-03-14):合并 v1.0 技术换算基础和 v2.0 执行规范,补充 line-height 关键发现
- v2.0:执行规范,强化输入输出契约和能力分级
- v1.0:技术换算基础,建立完整的映射表
📖 使用建议
对于 AI
- 首次加载:加载本主规范全文 + 附录索引
- 执行迁移:按 §13 的 10 步流程执行
- 查表映射:按需加载附录 A/B/C/D
- 验证输出:确保符合 §1.2 的输出物要求
对于开发者
- 快速上手:先读 §1-4 了解规则和决策
- 技术细节:需要时查阅 §5-12 的换算表
- 执行迁移:按 §13 的流程逐步完成
- 问题排查:回到对应章节查找解决方案
文档完整,可以开始迁移! 🚀