Files
Neo-ZQYY/apps/miniprogram - 副本/doc/migration-guide.md

561 lines
25 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# H5 → 微信小程序迁移实施指南
> 本文档是"规则化迁移 + AI 辅助 + 视觉验收"的完整实施方案。
> 适用于将 `docs/h5_ui/pages/*.html`Tailwind CSS + 原生 JS迁移为原生微信小程序页面。
> 试点页面:`notes`(备注记录)— 中低复杂度,验证流程可行性。
---
## 一、核心原则
**这是迁移工程,不是生成工程。**
- 规则先行标签映射、样式换算、事件转换有明确规则表AI 按规则执行
- 原型忠实H5 源码 + computed-styles + 截图是唯一视觉真相,不凭想象
- 组件化承接TDesign 组件优先,自定义组件按 design.md 接口定义
- 视觉回归兜底:每个页面转换后必须与 H5 截图逐项对比
- 增量验证:一个页面走完全流程再推进下一个
---
## 二、迁移流水线6 步)
```
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Step 1 │ │ Step 2 │ │ Step 3 │
│ 输入物冻结 │───▶│ 迁移审计 │───▶│ 规则化转换 │
│ (HTML/CSS/ │ │ (风险点+ │ │ (标签/样式/ │
│ 截图/交互) │ │ 替代方案) │ │ 事件/路由) │
└─────────────┘ └─────────────┘ └─────────────┘
┌─────────────┐ ┌─────────────┐ ▼
│ Step 6 │ │ Step 5 │ ┌─────────────┐
│ 验收签收 │◀───│ 差异修复 │◀───│ Step 4 │
│ (通过/打回) │ │ (截图diff+ │ │ 编译验证 │
│ │ │ 定点修复) │ │ (开发者工具) │
└─────────────┘ └─────────────┘ └─────────────┘
```
---
## 三、Step 1输入物冻结
每个页面转换前AI 必须加载以下材料(缺一不可):
| 序号 | 材料 | 路径 | 作用 |
|------|------|------|------|
| 1 | H5 源码 | `docs/h5_ui/pages/<page>.html` | 结构与样式的唯一真相 |
| 2 | 自定义 CSS | `docs/h5_ui/css/<page>.css`(如有) | 非 Tailwind 的自定义样式 |
| 3 | 交互说明 | `docs/h5_ui/interactions/<page>.md` | 状态变量、操作响应、页面状态枚举 |
| 4 | 设计 Token | `docs/h5_ui/design-tokens.json` | 颜色、间距、圆角、字号、阴影 |
| 5 | 图标映射表 | `docs/h5_ui/icon-mapping.md` | 图标处理方案TDesign/自定义/Emoji |
| 6 | 计算样式 | `docs/h5_ui/computed-styles.json` 中对应 key | 精确的 px 数值(如有) |
| 7 | 截图 | `docs/h5_ui/screenshots/<page>--*.png` | 视觉校验基线 |
| 8 | 转换规范 | `.kiro/steering/miniprogram-h5-conversion.md` | 强制规则 |
| 9 | 避坑指南 | `apps/miniprogram/doc/h5-to-miniprogram-pitfalls.md` | 22 个高频坑点 |
### 加载顺序
```
1. 转换规范 + 避坑指南(规则层)
2. 设计 Token + 图标映射(全局资源层)
3. H5 源码 + 自定义 CSS + 计算样式(页面源码层)
4. 交互说明(行为层)
5. 截图(视觉校验层)
```
---
## 四、Step 2迁移审计
读取 H5 源码后,先输出《迁移审计报告》,不写代码。
### 审计清单
| 审计项 | 输出内容 |
|--------|---------|
| A. 页面结构 | 主要区域划分header/list/card/footer组件化边界建议 |
| B. CSS 风险点 | 不支持的 CSS 特性清单 + 替代方案伪元素、backdrop-filter、clip-path 等) |
| C. Tailwind 展开 | 关键元素的 Tailwind 类 → WXSS 属性映射(取 computed-styles 精确值) |
| D. SVG/图标 | 内联 SVG 清单 + 处理方式TDesign/导出图片/Emoji |
| E. JS 交互 | DOM 操作 → setData 映射表 |
| F. 外部依赖 | CDN 资源Tailwind/Google Fonts的本地化方案 |
| G. 缺失信息 | 需要用户补充的材料清单 |
### 审计报告格式
```markdown
## <page-name> 迁移审计报告
### A. 页面结构
- 顶部导航栏sticky含返回按钮 + 标题)
- Tab 切换区(客户备注 / 助教备注)
- 备注列表wx:for 渲染,每条含文本 + 标签 + 时间)
### B. CSS 风险点
| 风险点 | 原因 | 影响 | 替代方案 | 验收方式 |
|--------|------|------|---------|---------|
| ... | ... | ... | ... | ... |
### C. 关键样式映射
| 元素 | Tailwind 类 | computed 值 | WXSS |
|------|------------|-------------|------|
| 备注卡片 | bg-white rounded-2xl p-4 shadow-sm | ... | ... |
### D. 图标处理
| 图标 | H5 实现 | 小程序方案 |
|------|---------|-----------|
| 返回箭头 | 内联 SVG | <t-icon name="chevron-left" /> |
### E. 交互映射
| H5 操作 | DOM 实现 | 小程序实现 |
|---------|---------|-----------|
| Tab 切换 | classList.toggle | setData({ activeTab }) + wx:if |
### F. 外部依赖
- Tailwind CDN → 手写 WXSS
- Google Fonts → 系统字体(-apple-system
### G. 缺失信息
- (列出需要用户补充的内容)
```
用户确认审计报告后,才进入 Step 3。
---
## 五、Step 3规则化转换
### 5.0 SVG 导出规则(强制,在转换前执行)
H5 原型中所有内联 `<svg>` 必须单独导出为 `.svg` 文件,小程序中通过 `<view>` + `<image>` 引用。
#### 规则
1. 扫描目标页面 H5 源码中的所有 `<svg>` 标签
2. 每个 SVG 导出为独立文件,存放路径:`apps/miniprogram/miniprogram/assets/icons/<name>.svg`
3. 命名规则:`icon-<用途>.svg`(如 `icon-wechat.svg``icon-clipboard.svg`Logo 类用 `logo-<名称>.svg`
4. 导出时保留原始 `viewBox``fill``path` 等属性,确保渲染一致
5. 小程序中引用方式:`<image src="/assets/icons/<name>.svg" mode="aspectFit" />`,必须指定宽高
6. 如果 TDesign 图标库有语义等价的图标(如返回箭头 → `chevron-left`),优先用 `<t-icon>`,不导出 SVG
7. 审计报告的「D. 图标处理」栏必须列出每个 SVG 的处理决策TDesign / 导出 SVG / Emoji
#### 为什么不用 TDesign icon 属性
TDesign `<t-button icon="xxx">``icon` 属性只支持 TDesign 内置图标名。微信 logo 等第三方品牌图标不在 TDesign 图标库中,传入无效名称会导致图标不显示。因此品牌图标、复杂自定义图标一律导出 SVG 文件,用 `<image>` 引用。
#### 已导出清单
| 文件名 | 来源页面 | 说明 |
|--------|---------|------|
| `logo-billiard.svg` | login | 台球 Logo已有 |
| `icon-wechat.svg` | login | 微信品牌图标 |
| `icon-clock-circle.svg` | reviewing | 时钟主图标stroke 风格TDesign 无等价) |
| `icon-forbidden.svg` | no-permission | 禁止符号主图标stroke 风格TDesign 无等价) |
> 每次迁移新页面时,将新导出的 SVG 追加到此清单。
### 5.1 标签映射(硬性规则)
| HTML | WXML | 说明 |
|------|------|------|
| `<div>` | `<view>` | 容器 |
| `<span>` / `<p>` | `<text>` | 文本必须用 `<text>` 包裹 |
| `<a>` | `<navigator>``bindtap` + `wx.navigateTo` | |
| `<img>` | `<image mode="">` | 必须指定 mode 和宽高 |
| `<svg>` 内联 | `<image src="xx.svg">``<t-icon>` | 不支持内联 SVG |
| `<ul>/<li>` | `<view wx:for>` | 无列表语义标签 |
| `<button>` | `<t-button>` | TDesign 优先 |
| `<input>` | `<t-input>` | TDesign 优先 |
| `<select>` | `<t-picker>` | 完全不同的交互 |
| `<h1>`~`<h6>` | `<text>` + 样式类 | 无语义标题标签 |
**严禁在 WXML 中使用 HTML 标签。**
### 5.2 样式转换规则
#### 一屏页面布局模式(强制)
对于 H5 原型中一屏显示完毕、不需要滚动的页面(如 login、reviewing、no-permission 等),必须使用以下布局模式:
```css
.page {
height: 100vh; /* 固定一屏高度,不用 min-height */
display: flex;
flex-direction: column;
box-sizing: border-box; /* padding-top 从 100vh 中扣除 */
overflow: hidden; /* 防止内容溢出产生滚动 */
/* padding-top 由 JS statusBarHeight 动态设置 */
}
.hero { flex: 1; } /* 主内容区域占满剩余空间,内部垂直居中 */
.bottom-area { /* 固定高度,不参与 flex 伸缩 */ }
```
关键点:
- `height: 100vh` + `box-sizing: border-box` → padding-top状态栏从总高度中扣除不会导致底部溢出
- 主内容区域用 `flex: 1` 自适应剩余空间,内部用 `justify-content: center` 垂直居中
- 底部操作区固定高度,不设 `flex`
- 如果页面内容可能超过一屏(如 apply 的表单页),改用 `min-height: 100vh` + 允许滚动
#### 状态栏适配(强制)
所有 `navigationStyle: "custom"` 的页面,必须:
1. TS 中 `onLoad` 获取 `wx.getSystemInfoSync().statusBarHeight`
2. WXML 中 `.page``style="padding-top: {{statusBarHeight}}px;"`
3. WXSS 中 `.page``box-sizing: border-box;`(确保 padding 不增加总高度)
4. 禁止使用 `env(safe-area-inset-top)`(部分机型不生效)
#### rpx 换算
```
H5 px 值 × 2 = rpx 值(基于 375px → 750rpx
Tailwind spacing: 1 unit = 4px = 8rpx
```
#### Tailwind → WXSS 速查表
| Tailwind | WXSS |
|----------|------|
| `p-4` | `padding: 32rpx;` |
| `px-4` | `padding-left: 32rpx; padding-right: 32rpx;` |
| `m-3` | `margin: 24rpx;` |
| `gap-3` | `gap: 24rpx;` |
| `space-y-3` | 子元素 `margin-top: 24rpx;`(首个除外) |
| `rounded-2xl` | `border-radius: 32rpx;` |
| `text-sm` | `font-size: 28rpx;` |
| `text-base` | `font-size: 32rpx;` |
| `text-xs` | `font-size: 24rpx;` |
| `font-medium` | `font-weight: 500;` |
| `font-semibold` | `font-weight: 600;` |
| `leading-relaxed` | `line-height: 1.625;` |
| `shadow-sm` | `box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.05);` |
| `flex` | `display: flex;` |
| `flex-col` | `flex-direction: column;` |
| `items-center` | `align-items: center;` |
| `justify-between` | `justify-content: space-between;` |
| `flex-1` | `flex: 1;` |
| `min-h-screen` | `min-height: 100vh;` |
| `sticky top-0` | `position: sticky; top: 0;` |
| `z-10` | `z-index: 10;` |
| `bg-white` | `background-color: #ffffff;` |
| `bg-gray-1` | `background-color: #f3f3f3;` |
| `text-gray-13` | `color: #242424;` |
| `text-gray-6` | `color: #a6a6a6;` |
| `border-b border-gray-2` | `border-bottom: 2rpx solid #eeeeee;` |
| `backdrop-blur-sm` | ❌ 不支持,改为 `rgba()` 半透明 |
#### 颜色值参照 design-tokens.json
```
primary: #0052d9 primary-light: #ecf2fe
success: #00a870 warning: #ed7b2f error: #e34d59
gray-1 ~ gray-13: 见 design-tokens.json
```
#### 不支持的 CSS 替代方案
| CSS 特性 | 替代方案 |
|----------|---------|
| `backdrop-filter: blur()` | `background: rgba(255,255,255,0.95);` |
| `*` 通配符选择器 | 逐个元素设置 |
| `::before` / `::after` | 额外 `<view>` 元素模拟(小程序部分支持伪元素,复杂场景用 DOM |
| 远程 `@font-face` | `wx.loadFontFace()` 或系统字体 |
| `clip-path` | 改为图片或 CSS 渐变近似 |
| `blur-xl`Tailwind | 去掉或改为纯色 |
### 5.3 事件转换规则
| H5 | 小程序 | 说明 |
|----|--------|------|
| `onclick="fn()"` | `bindtap="fn"` | 不能传参 |
| `onclick="fn(id)"` | `data-id="{{id}}" bindtap="fn"` | dataset 传参 |
| `addEventListener` | 不支持 | 只能声明式绑定 |
| `event.target.value` | `e.detail.value` | 取值路径不同 |
| `event.preventDefault()` | `catchtap` | catch 前缀阻止冒泡 |
| `classList.toggle('active')` | `setData({ active: !this.data.active })` + `class="{{active ? 'on' : ''}}"` | |
| `innerHTML = '...'` | `setData({ content: '...' })` + WXML 数据绑定 | |
| `history.back()` | `wx.navigateBack()` | |
| `window.location.href` | `wx.navigateTo({ url: '...' })` | |
| `localStorage.setItem` | `wx.setStorageSync` | |
| `alert()` / `confirm()` | `wx.showToast()` / `wx.showModal()` | |
### 5.4 路由转换规则
| 场景 | 小程序 API | 说明 |
|------|-----------|------|
| 普通页面跳转 | `wx.navigateTo` | 保留当前页,页面栈 +1 |
| TabBar 页面跳转 | `wx.switchTab` | 必须用 switchTabnavigateTo 会报错 |
| 替换当前页 | `wx.redirectTo` | 关闭当前页 |
| 清空页面栈 | `wx.reLaunch` | 登录/登出场景 |
| 返回上一页 | `wx.navigateBack` | 页面栈 -1 |
**TabBar 页面task-list、board-finance、my-profile**
### 5.5 转换执行顺序
```
1. 创建页面 4 文件骨架(.wxml / .wxss / .ts / .json
2. 在 .json 中注册 usingComponentsTDesign 组件 + 自定义组件)
3. 转换 WXML 结构HTML 标签 → WXML 标签,保持层级一致)
4. 转换 WXSS 样式Tailwind → 手写 WXSS取 computed-styles 精确值)
5. 转换 TS 逻辑DOM 操作 → setData事件绑定 → bindtap
6. 设置 Mock 数据(贴近真实 API 格式,标记 TODO
7. 处理三态loading / empty / normal / error
```
---
## 六、Step 4编译验证
在微信开发者工具中检查:
| 检查项 | 合格标准 |
|--------|---------|
| WXML 编译 | 无编译错误(特别注意 `.toFixed()` 等 JS 方法不能在 WXML 中使用) |
| WXSS 编译 | 无警告(检查不支持的选择器) |
| 控制台 | 无 JS 运行时错误 |
| 图片加载 | 无 404/500 错误(所有 `/assets/` 引用的文件必须存在) |
| 组件注册 | 无 "component not found" 警告 |
| 路由跳转 | 无 "navigateTo:fail" 错误 |
---
## 七、Step 5差异修复
### 7.1 截图对比
用户在微信开发者工具中截图,与 `docs/h5_ui/screenshots/<page>--*.png` 逐项对比。
### 7.2 差异追踪表
| 差异描述 | 位置 | 严重度 | 可能原因 | 修复方案 | 修复代价 |
|---------|------|--------|---------|---------|---------|
| 卡片圆角偏小 | 备注卡片 | P1 | rpx 换算错误 | 改为 32rpx | 低 |
| 标签颜色偏差 | tag-coach | P1 | 颜色值不准确 | 取 computed-styles 精确值 | 低 |
| 间距不一致 | 列表间距 | P0 | space-y-3 未正确转换 | 改为 margin-top: 24rpx | 低 |
### 7.3 修复原则
- 只输出需要改动的文件和改动段落diff 风格),不整文件重贴
- 优先使用 flex/盒模型的确定性方案,不用"碰运气"的魔法数
- rpx 换算统一,严禁同一类间距混用 rpx 和 px
- 每次修复后重新编译验证,防止修 A 坏 B
---
## 八、Step 6验收签收
### 逐项验收清单
| 验收项 | 怎么看 | 合格标准 | 常见失败表现 |
|--------|--------|---------|-------------|
| 布局结构 | 对比截图整体布局 | 区域划分、层级关系一致 | 元素错位、层级混乱 |
| 间距系统 | 对比元素间距 | 与 H5 截图一致±4rpx 容差) | 间距过大/过小 |
| 字体系统 | 对比字号、字重、行高 | 与 design-tokens 一致 | 字号偏差、行高不对 |
| 颜色 | 对比背景色、文字色、边框色 | 与 design-tokens 一致 | 颜色偏差 |
| 圆角 | 对比卡片、按钮圆角 | 与 design-tokens 一致 | 圆角过大/过小 |
| 阴影 | 对比卡片阴影 | 有阴影且不突兀 | 无阴影或阴影过重 |
| 图标 | 对比图标位置、大小、颜色 | TDesign 图标正确显示 | 图标缺失或错位 |
| 交互完整性 | 按交互说明逐项操作 | 所有操作有正确响应 | 点击无反应、状态不切换 |
| 三态处理 | 切换 loading/empty/error | 三种状态均有对应 UI | 缺少空状态或加载态 |
| 安全区 | 刘海屏设备检查 | 内容不被刘海遮挡 | 顶部内容被裁切 |
---
## 九、试点页面notes备注记录
### 选择理由
- 中低复杂度:简单列表 + Tab 切换 + 标签样式
- 覆盖核心转换场景Tailwind → WXSS、事件绑定、列表渲染、三态处理
- 有完整材料HTML + CSS + 交互说明 + 截图
- 验证周期短:预计 1 轮即可完成
### 需要加载的材料
```
docs/h5_ui/pages/notes.html
docs/h5_ui/css/notes.css
docs/h5_ui/interactions/notes.md
docs/h5_ui/design-tokens.json
docs/h5_ui/icon-mapping.md
docs/h5_ui/screenshots/notes--*.png
docs/h5_ui/computed-styles.jsonnotes key如有
```
### 预期产出
```
miniprogram/pages/notes/notes.wxml
miniprogram/pages/notes/notes.wxss
miniprogram/pages/notes/notes.ts
miniprogram/pages/notes/notes.json
```
---
## 十、页面迁移优先级
按模块分组,每组内按复杂度从低到高排列:
| 批次 | 页面 | 复杂度 | 说明 |
|------|------|--------|------|
| 试点 | notes | 低 | 验证流程 |
| 第 1 批 | login, apply, reviewing, no-permission | 低 | 认证流程(已有实现,需重写) |
| 第 2 批 | task-list, task-detail | 中-高 | 任务模块核心 |
| 第 3 批 | task-detail-callback, task-detail-priority, task-detail-relationship | 中 | 任务详情变体 |
| 第 4 批 | performance, performance-records | 中 | 绩效模块 |
| 第 5 批 | board-finance, board-customer, board-coach | 高 | 看板模块(筛选+吸顶+复杂布局) |
| 第 6 批 | customer-detail, customer-service-records, coach-detail | 中 | 详情模块 |
| 第 7 批 | chat, chat-history | 中 | 对话模块 |
| 第 8 批 | my-profile | 中 | 个人中心 |
---
## 十一、需要用户补充的内容
### P0阻塞试点
| 材料 | 状态 | 说明 |
|------|------|------|
| notes 页面截图 | ⚠️ 待确认 | 确认 `docs/h5_ui/screenshots/notes--*.png` 是否存在 |
| notes 的 computed-styles | ⚠️ 待确认 | 确认 `computed-styles.json` 中是否有 notes key |
### P1提升还原度
| 材料 | 状态 | 说明 |
|------|------|------|
| Banner 背景图片 | ❌ 缺失 | icon-mapping.md 规划了用 Playwright 截取 Banner但实际图片未导出 |
| AI 图标图片 | ❌ 缺失 | icon-ai-float.png / icon-ai-inline.png / icon-ai-badge.png 需要从 H5 截取 |
| 其他页面的 computed-styles | ⚠️ 部分缺失 | 当前仅 5 个页面有数据,其余 19 个缺失 |
### P2后续批次需要
| 材料 | 状态 | 说明 |
|------|------|------|
| home-settings 交互说明 | ❌ 缺失 | |
| ai-icon-demo 交互说明 | ❌ 缺失 | |
---
## 十二、与现有文档的关系
| 文档 | 职责 | 本指南的关系 |
|------|------|-------------|
| `miniprogram-h5-conversion.md`steering | 强制转换规则 | 本指南引用其规则,不重复 |
| `h5-to-miniprogram-pitfalls.md` | 避坑清单 | 本指南引用其坑点,不重复 |
| `h5-input-material-guide.md` | 输入材料准备规范 | 本指南引用其格式要求 |
| `howtodo.md` | 6 阶段工作流提示词 | 本指南是其具体化实施版本 |
| `design.md`spec | 组件接口 + 数据模型 | 本指南引用其组件定义 |
---
## 十三、实战踩坑记录
> 本节记录迁移过程中实际遇到的坑和解决方案,按发现时间倒序排列。每次迁移新页面遇到新坑时追加。
### P1WXML 中不能调用 JS 方法
- 触发页面:所有页面
- 现象:`{{price.toFixed(2)}}` 编译报错
- 原因WXML 模板表达式不支持 JS 方法调用(`.toFixed()``.map()``.filter()` 等)
- 解决:创建 WXS 模块 `utils/format.wxs`,在 WXML 中 `<wxs src="..." module="fmt" />`,用 `{{fmt.toFixed(price, 2)}}`
### P2TabBar 页面不能用 navigateTo
- 触发页面task-list、board-finance、my-profile
- 现象:`navigateTo:fail` 静默失败
- 原因TabBar 页面必须用 `wx.switchTab``navigateTo` / `redirectTo` 均无效
- 解决:跳转前判断目标是否 TabBar 页面,是则用 `switchTab`
### P3图片 500 错误(资源文件不存在)
- 触发页面:所有引用 `/assets/images/*.png``/assets/icons/icon-ai-*.png` 的页面
- 现象:控制台大量 500 错误
- 原因:代码引用了不存在的图片文件
- 解决:用 CSS 渐变、emoji 文本、`<t-icon>` 替代所有不存在的图片引用;仅保留确实存在的文件(如 `logo-billiard.svg`
### P4env(safe-area-inset-top) 部分机型不生效
- 触发页面notes、login所有 `navigationStyle: "custom"` 的页面)
- 现象iPhone 刘海屏顶部内容被状态栏遮挡,部分安卓机型也有此问题
- 原因:`env(safe-area-inset-top)` 在部分机型/基础库版本下返回 0
- 解决TS 中 `onLoad` 获取 `wx.getSystemInfoSync().statusBarHeight`WXML 中动态设置 `style="padding-top: {{statusBarHeight}}px;"`
- 标准模式:见 5.2 节「状态栏适配」
### P5statusBarHeight padding 导致一屏页面底部溢出
- 触发页面login所有一屏不滚动的页面
- 现象:底部按钮和协议文字被推到屏幕外
- 原因:`min-height: 100vh` + `padding-top: Xpx` = 实际高度 > 100vh
- 解决:改为 `height: 100vh` + `box-sizing: border-box`padding 从总高度中扣除
- 标准模式:见 5.2 节「一屏页面布局模式」
### P6TDesign Button icon 属性不支持自定义图标
- 触发页面login
- 现象:`<t-button icon="logo-wechat">` 微信图标不显示
- 原因TDesign `icon` 属性只接受内置图标名,微信 logo 不在内置库中
- 解决:放弃 `t-button`,改为原生 `<view>` + `<image src="/assets/icons/icon-wechat.svg">` 手动组合按钮
- 规则:品牌图标、复杂自定义图标一律导出 SVG 文件,用 `<image>` 引用(见 5.0 节)
### P7TDesign Button 默认样式覆盖自定义 WXSS
- 触发页面login
- 现象:按钮圆角过大(接近胶囊形)、禁用态颜色不是预期的 `#dcdcdc`
- 原因TDesign Button 内部样式优先级高于外部 `t-class` 覆盖,`!important` 也不一定生效
- 解决:对于需要高度定制的按钮,直接用原生 `<view>` 实现,完全绕开 TDesign 样式干扰
- 原则TDesign 组件适合"接近默认样式"的场景;与原型差异大时,原生实现更可控
### P8小程序 WXSS 不支持 `::before` / `::after` 伪元素
- 触发页面reviewing
- 现象:尝试用 `::before` 添加背景图案层,编译无报错但不渲染
- 原因:微信小程序 WXSS 不支持 CSS 伪元素
- 解决:用实际的 `<view class="bg-pattern">` 替代伪元素absolute 定位覆盖全屏
- 规则:所有需要伪元素的场景(装饰层、分隔线、角标等),一律用 WXML `<view>` 实现
### P9小程序 WXSS 不支持 `url("data:image/svg+xml,...")` 内联 SVG
- 触发页面reviewing
- 现象H5 用 `background-image: url("data:image/svg+xml,...")` 实现十字纹背景,小程序中不渲染
- 原因:小程序 WXSS 的 `background-image` 不支持 data URI仅支持网络图片和 base64 图片)
- 解决:用 `repeating-linear-gradient` 组合模拟纹理图案;或用实际图片文件
- 规则H5 中的 SVG 背景图案,迁移时优先用 CSS 渐变模拟;效果不佳时导出为 PNG/base64
### P10小程序不支持 `filter: blur()` CSS 属性
- 触发页面reviewing
- 现象H5 用 `blur-xl`Tailwind实现图标背景光晕的模糊效果小程序中无效
- 原因:微信小程序 WXSS 不支持 `filter` 属性
- 解决:用更大尺寸的 `radial-gradient` 模拟模糊扩散效果(扩大元素尺寸 + 调整渐变衰减曲线)
- 参数参考:原始 256rpx → 扩大到 320rpxgradient 从 `0.18 → 0.06 → transparent` 三段衰减
### P11Tailwind `max-w-sm` 在小程序中的换算需考虑容器 padding
- 触发页面reviewing
- 现象:进度卡片 `max-w-sm = 384px = 768rpx` 直接换算后卡片过宽
- 原因H5 中 `max-w-sm` 受外层 `px-8`32px padding约束实际可用宽度 ≈ 320px小程序中 content 区域的 padding 和 max-width 叠加效果不同
- 解决:实测调整 `max-width` 值(本例最终为 550rpx不能机械换算
- 规则:涉及 `max-w-*` 的元素,迁移后必须在真机/模拟器中目测确认宽度,按实际效果微调
### P12H5 Tailwind 颜色变体需逐一核对(如 `bg-amber-300` ≠ `bg-warning`
- 触发页面reviewing
- 现象:装饰点 dot-2 在 H5 中用 `bg-amber-300`#fcd34d),迁移时误用了 `bg-warning`#ed7b2f
- 原因Tailwind 的 amber/orange/yellow 色系有多个变体,不能一律映射为 design-tokens 中的 `warning`
- 解决:逐个检查 H5 中的颜色类名,查 Tailwind 色板取精确 hex 值
- 规则:迁移时遇到非 design-tokens 定义的 Tailwind 颜色,必须查 Tailwind 官方色板确认精确值
---
## 附录:相关文档索引
- 转换规范:`.kiro/steering/miniprogram-h5-conversion.md`
- 避坑指南:`apps/miniprogram/doc/h5-to-miniprogram-pitfalls.md`
- 输入材料指南:`apps/miniprogram/doc/h5-input-material-guide.md`
- 工作流提示词:`apps/miniprogram/doc/howtodo.md`
- 设计文档:`.kiro/specs/p52-miniapp-fe-all-pages/design.md`
- 设计 Token`docs/h5_ui/design-tokens.json`
- 图标映射:`docs/h5_ui/icon-mapping.md`
- H5 原型:`docs/h5_ui/pages/`
- 交互说明:`docs/h5_ui/interactions/`
- 截图:`docs/h5_ui/screenshots/`