This commit is contained in:
乘风
2026-02-03 11:50:59 +08:00
parent a7d781a25b
commit 9a08273541
7 changed files with 213 additions and 383 deletions

View File

@@ -17,6 +17,59 @@ Kbone 是腾讯提供的 Web 与小程序同构解决方案,允许使用 React
---
## Next 项目 → 小程序 最优转化方式
适用于:**现有 Next.js 前端 + newppKbone 模板)**,以**适配**方式转化,保持功能与视觉一致。
### 架构约定
| 角色 | 说明 |
|------|------|
| **newpp** | Kbone 构建源:多入口 React 应用,`npm run mp` 输出到 `dist/mp/common/` |
| **miniprogram** | 小程序壳:`app.js`/`app.json`/`custom-tab-bar` 等,构建后**合并** newpp 的页面与 common |
| **Next 项目根目录** | Web 端:`app/``components/`、Tailwind与 newpp 共享业务逻辑时可被 alias 或复制 |
### 转化步骤概要
1. **以 newpp 为唯一 Kbone 构建源**
-`newpp/build/miniprogram.config.js` 中按 Next 路由配置 `router`(每页单独配置,不用 `other`)。
-`newpp/build/webpack.mp.config.js` 中为每个页面配置 `entry`,且 `isOptimize = process.env.NODE_ENV === 'production'`
2. **适配层(必须)**
- `adapters/env.js``isMiniProgram()``typeof wx !== 'undefined' && wx.getSystemInfoSync`)。
- `adapters/request.js`Web 用 `fetch`,小程序用 `wx.request`,统一返回 Promise。
- `adapters/storage.js`Web 用 `localStorage`,小程序用 `wx.getStorageSync`/`setStorageSync`
- `adapters/router.js`Web 用 `window.location` 或 Next `router`,小程序用 `wx.navigateTo`/`wx.reLaunch`;路径转小程序页面路径 `toMpPath(path)`
- **功能控制一致**:与 Next 端相同,用同一套 API`/api/db/config`)和条件渲染(如 `features.matchEnabled` 控制「找伙伴」入口),不写死开关。
3. **UI 与页面来源**
- **方案 A推荐起步**:在 newpp 内维护页面与组件,从 Next 的 `app/**/page.tsx``components/**` 复制并改为 JSX + 适配器调用(去掉 Next 专属的 `Link`/`useRouter`/`usePathname`,改用适配层)。
- **方案 B**:在 newpp 的 webpack 中配置 `resolve.alias`,直接引用项目根目录的共享组件目录(需保证组件仅用 React + 适配层,无 `window`/`document`/Next 专属 API
4. **miniprogram.config.js 要点**
- `router`:每个页面单独 key例如 `index``chapters``read``my``match`,对应 `entry` 与小程序页面路径。
- 动态底部导航:不配置原生 `tabBar`,在 `appExtraConfig` 中不写 `tabBar`;底部栏用 React 组件 + `wx.reLaunch` 跳转。
5. **样式兼容(与 Next 视觉一致)**
- Grid → Flex`boxSizing: 'border-box'`、必要时 `lineHeight`)。
- `backdrop-filter` / `position: sticky` 等不支持则用占位或纯色/渐变替代,保证布局不错乱。
- 单位:小程序侧可用 rpx与 Web 的 rem/px 按设计稿做一次换算或共用同一套换算规则。
6. **构建与合并**
- 在 newpp 执行 `NODE_ENV=production npm run build:mp`,将 `dist/mp/common/` 及 mp-plugin 生成的页面目录合并到 `miniprogram/`
- 合并时保留 miniprogram 壳的 `app.js` 全局数据与生命周期,只覆盖/新增 Kbone 生成的页面与 common 资源。
### 与 Kbone 规则的关系
- **router**:遵循本技能「核心配置规范」——每页单独配置、不用 `other`
- **底部导航**:遵循「问题 4底部导航动态显示」——不配置原生 tabBar用自定义组件 + `wx.reLaunch`
- **API/兼容**:遵循「跨平台适配层」与「问题 3URLSearchParams」——全部走适配层避免 Web 独有 API。
- **样式**:遵循「问题 1样式错位」与 troubleshooting 中的 Grid/Flex、box-sizing、lineHeight 等。
详细排查与示例见本目录下 `troubleshooting.md` 以及项目 `开发文档/8、部署/`
---
## 核心配置规范
### 1. miniprogram.config.js 配置

View File

@@ -0,0 +1,110 @@
# Next → 小程序 转化参考(详细步骤)
`SKILL.md` 中「Next 项目 → 小程序 最优转化方式」对应,用于按步骤执行转化。
---
## 1. 架构与目录约定
| 目录/产物 | 作用 |
|-----------|------|
| `newpp/` | Kbone 源码:多入口 React构建输出到 `newpp/dist/mp/` |
| `miniprogram/` | 小程序壳:`app.js``app.json``custom-tab-bar`、空白页面占位等 |
| Next 根目录 `app/``components/` | Web 端页面与组件;可被 newpp 复制或通过 alias 引用 |
构建后:将 `newpp/dist/mp/` 下的页面与 `common/` 合并进 `miniprogram/`,保留壳的 `app.js` 全局逻辑。
---
## 2. newpp 配置
### 2.1 miniprogram.config.js
- `router`:每个页面单独 key对应 Next 路由,**不要使用 `other` 数组**。
- 动态底部导航:`appExtraConfig` 中**不配置** `tabBar`,用自定义 React 组件 + `wx.reLaunch`
- `global`:建议 `rem: true``pageStyle: true`
- `pages`:为每个页面配置 `extra.navigationBarTitleText`
示例(按实际路由调整):
```javascript
router: {
index: ['/', '/(index)?', '/index.html'],
chapters: ['/chapters', '/chapters.html'],
read: ['/read/:id', '/read.html'],
my: ['/my', '/my.html'],
match: ['/match', '/match.html'],
},
appExtraConfig: {
sitemapLocation: 'sitemap.json',
// 不配置 tabBar
},
```
### 2.2 webpack.mp.config.js
- `entry`:每个页面一个入口,例如 `index``chapters``read``my``match`,指向 newpp 内对应入口 JSX。
- `isOptimize``const isOptimize = process.env.NODE_ENV === 'production'`,生产构建时再压缩。
- `optimization.splitChunks`:中小型项目建议 `splitChunks: false`,避免 chunk 缺失;大型项目再考虑固定命名 cacheGroups。
---
## 3. 适配层(必须)
在 newpp 内(或共享到根目录再被引用)实现:
| 文件 | 职责 |
|------|------|
| `adapters/env.js` | `isMiniProgram()``typeof wx !== 'undefined' && wx.getSystemInfoSync` |
| `adapters/request.js` | Web`fetch`;小程序:`wx.request`,统一返回 Promise |
| `adapters/storage.js` | Web`localStorage`;小程序:`wx.getStorageSync`/`setStorageSync` |
| `adapters/router.js` | Web`window.location` 或 Next Router小程序`wx.navigateTo`/`wx.reLaunch`,路径用 `toMpPath(path)` 转成小程序页面路径 |
业务代码**只**通过适配层访问请求、存储、路由,不直接使用 `window``document``localStorage``URLSearchParams` 等。
---
## 4. 功能控制一致
与 Next 端保持一致:
- 功能开关来自同一 API例如 `/api/db/config``features.matchEnabled`
- 底部导航「找伙伴」等入口根据该配置条件渲染,不在小程序端写死。
- 支付方式、营销二维码等同样由 API 配置驱动,两端逻辑一致。
---
## 5. UI 来源策略
- **复制适配**:从 Next 的 `app/**/page.tsx``components/**` 复制到 newpp改为 JSX用适配层替代 `Link`/`useRouter`/`usePathname`/`fetch`
- **Alias 引用**:在 newpp 的 webpack `resolve.alias` 中指向项目根目录的共享组件目录,保证该目录内仅用 React + 适配层,无 Next 专属 API。
---
## 6. 样式兼容(与 Next 视觉一致)
- **Grid → Flex**:所有 Grid 布局改为 Flex并加 `boxSizing: 'border-box'`、必要时 `lineHeight`
- **backdrop-filter / sticky**:不支持则用纯色、渐变或占位,保证布局不错位。
- **单位**:小程序侧可用 rpx与 Web 的 rem/px 按设计稿统一换算。
详见 `troubleshooting.md` 中的「样式问题」小节。
---
## 7. 构建与合并流程
1. 在 newpp 执行:`NODE_ENV=production npm run build:mp`
2.`newpp/dist/mp/` 下生成的页面目录及 `common/` 复制/合并到 `miniprogram/`
3. 保留 miniprogram 壳的 `app.js`(全局 data、onLaunch、onShow 等),仅覆盖或新增 Kbone 生成的页面与 common。
4. 用微信开发者工具打开 `miniprogram/` 根目录,编译并测试。
---
## 8. 检查清单
- [ ] miniprogram.config.js每页单独 router`other`;未配置原生 tabBar。
- [ ] webpack.mp.config.js每页有 entryisOptimize 按 NODE_ENV中小型项目 splitChunks 为 false。
- [ ] 适配层env、request、storage、router 已实现并在业务中统一使用。
- [ ] 功能开关与 Next 一致,来自同一 API。
- [ ] 样式:无 GridFlex 已加 boxSizing/lineHeight不支持特性已替代。
- [ ] 合并后 app.js 未被错误覆盖,页面路径与 app.json 一致。

View File

@@ -1,5 +1,20 @@
# Kbone 常见问题排查指南
## 从 Next 项目迁移到小程序
**先读**:本技能 `SKILL.md` 中的「Next 项目 → 小程序 最优转化方式」章节。
**要点**
-**newpp** 为 Kbone 构建源,**miniprogram** 为壳,构建后合并产物。
- 必须做 **适配层**`env``request``storage``router`;功能开关与 Next 一致,用同一 API`/api/db/config``features.matchEnabled`)。
- **UI**:在 newpp 内复制并适配 Next 的页面/组件,或通过 webpack alias 引用根目录共享组件(无 Next 专属 API
- **配置**`miniprogram.config.js` 每页单独 router、不配原生 tabBar`webpack.mp.config.js``isOptimize = process.env.NODE_ENV === 'production'`,中小型项目建议 `splitChunks: false`
- **样式**Grid 改 Flex`boxSizing`/`lineHeight`;不支持特性用兼容写法或替代。
遇到具体报错时,在下方「编译问题」「运行时问题」「样式问题」中按类型排查。
---
## 编译问题
### 1. chunk 文件缺失错误

View File

@@ -1,159 +0,0 @@
---
name: web-to-miniprogram-conversion
description: Ensures complete 1:1 style migration and visual parity when converting Next.js to WeChat Mini Program (Kbone). Covers style compatibility mapping,补齐兼容 for Grid/backdrop/sticky/shadow/selectors, and visual parity checklist. Use when migrating Web to miniprogram, doing style conversion, or when the user asks for 100% style migration or visual consistency.
---
# Web 转小程序转化过程技能
本技能提供「Web 前端转微信小程序」时的注意事项与清单,与 Kbone 配置互补使用。
**前置**Kbone 搭建与配置见 [.cursor/skills/kbone-miniprogram/SKILL.md](../kbone-miniprogram/SKILL.md)。本文聚焦**转化过程**中的样式、动态 UI、请求、存储、路由等细节。
---
## 样式迁移目标与原则
**目标**Next 转小程序过程中,实现 **完整、1:1、100% 样式迁移**,小程序端与 Web 端**视觉一致**。
**原则**
- 两端框架 CSS 能力有差异时,**不做删减**,而是做**补齐兼容**:用小程序支持的写法实现**等价的视觉效果**(颜色、字号、间距、圆角、对齐、安全区等一致)。
- 凡无法用原生 CSS 完全复刻的(如 backdrop-filter、多阴影、部分选择器用**视觉等价替代**(如毛玻璃→同色半透明、多阴影→单阴影或边框)并记录在 [reference.md - 样式兼容映射表](reference.md#web小程序-样式兼容映射表)。
- 验收标准:同一页面在 Web 与小程序上并排对比,**字体、颜色、间距、圆角、对齐、安全区**等肉眼无差异。
---
## 一、样式转化与补齐兼容
### 1.1 布局Grid → Flex视觉等价
- 小程序对 CSS Grid 支持不完整,易错位。
- **补齐兼容**:所有 `grid` / `grid-cols-*` 改为 Flex**保持视觉一致**
- 父:`display: flex``flexDirection: 'row'`(多列)或 `'column'`(多行);`flexWrap: 'wrap'` 若需换行。
- 子:`flex: 1` 平分,或 `flex: '0 0 25%'` 等固定比例;**宽度/比例与 Web 上列数一致**(如 4 列即每项约 25%)。
- **gap**:小程序支持则用 `gap`;不支持则用子项 `margin`(如 `marginRight`/`marginBottom`)或父 `padding`**数值与 Web 一致**(如 gap-3 → 12px 或 24rpx
- 涉及底部导航、统计卡片、菜单列表、弹窗内多列、Dialog 居中(用 `flex` + `alignItems: 'center'` + `justifyContent: 'center'`)等。
### 1.2 必加属性(保证视觉一致)
- **box-sizing**:有 padding/border 的容器**必须**加 `boxSizing: 'border-box'`(或 Tailwind `box-border`),避免撑破布局导致错位、溢出。
- **line-height**:图标+文字、多行文案处**显式**设 `lineHeight`(如 1、1.2、1.5),与 Web 一致,避免垂直错位。
- **width**:需要占满的块加 `width: '100%'``flex: 1`,避免窄屏下宽度不一致。
### 1.3 需替换或降级的样式(视觉等价补齐)
| 类型 | Web 常见用法 | 小程序补齐兼容(视觉一致) |
|------|--------------|----------------------------|
| 毛玻璃 | `backdrop-filter` / `backdrop-blur-*` | 取 Web 背景主色 + 透明度:如 `backgroundColor: 'rgba(0,0,0,0.95)'``'rgba(28,28,30,0.95)'`**与 Web 视觉效果接近**,不删该区域。 |
| 吸顶 | `position: sticky` | `position: 'fixed'``top: 0``left/right: 0`**同高同背景**;页面内容区加 `paddingTop` 与顶栏高度一致,避免被遮挡。 |
| 安全区 | `env(safe-area-inset-*)` | 小程序支持则保留;构建后确认 WXSS 未丢失;`.safe-top`/`.safe-bottom` 在小程序端用相同 `padding` 或类实现,**数值一致**。 |
| 多阴影 | `box-shadow: a, b, c` | Skyline 仅支持单阴影:保留主阴影或用 `border` + 单 `boxShadow` 近似,**颜色与扩散与 Web 主阴影一致**。 |
| 伪类间距 | `:last-child { margin }` | 改为给最后一项加 class 或内联 `marginBottom: 0`,其余项统一 `marginBottom`**间距数值与 Web 一致**。 |
### 1.4 Tailwind / CSS 变量
- Tailwind v4 的 `@theme inline``@layer` 等需确认 Kbone 构建链支持;`:root` 的 CSS 变量(如 oklch一般可用若有问题再在构建侧替换为固定值。
- 单位:若 Kbone 配置 `global.rem: true`Tailwind 的 rem 会按小程序规范转换。
### 1.5 样式补充选择器、单位、Skyline、动画
- **WXSS 选择器**:仅支持 `.class``#id``element``element, element``::before`/`::after`**不支持**通配 `*`、属性选择器 `[attr]`、伪类 `:hover`/`:not()`/`:first-child`Skyline 高版本起部分伪类支持,需看基础库)。
- **单位**:竖屏以 **rpx** 为主(规定屏幕宽 750rpx字体建议 rpx 或页面设 `page` 初始字号,避免 px 随系统字体变化;横屏可用 **vmin**100rpx ≈ 100vmin/7.5)。
- **Skyline 渲染**:若启用 Skyline默认 `display: flex``box-sizing: border-box``flex-direction: column`,与 Web 不同;可配置 `defaultDisplayBlock: true``defaultContentBox: true` 对齐 Web。`overflow: scroll` 不支持,需用 `scroll-view``position: sticky` 用组件 `sticky-header`/`sticky-section` 替代;`backdrop-filter` 有多项限制(多函数、与 opacity 混用、blur 表现不一致);`box-shadow` 不支持多阴影叠加。
- **动画与性能**CSS 动画transform、keyframes会影响性能宜少用静态样式写 class动态写 style避免全部塞进 style。
- 更多见 [reference.md - 样式补充(联网核查)](reference.md#样式补充联网核查)。
### 1.6 视觉一致验收
- **单位统一**Web 用 rem/px 的数值,小程序侧用 rpx 或 remKbone 开启 rem 时)时,**换算后与 Web 视觉一致**(如 16px → 32rpx 或 1rem 按基准换算)。
- **颜色**CSS 变量、hex、rgba 等在小程序侧**原样保留或替换为同值**oklch 若不支持则转为 rgb/hex
- **字体与行高**`fontSize``fontWeight``lineHeight` 与 Web 一致;图标+文字对齐用 `lineHeight``alignItems: 'center'` 保证。
- **间距与圆角**padding、margin、borderRadius 数值与 Web 一致px→rpx 按 750 基准换算)。
- **对齐**flex 的 `alignItems``justifyContent` 与 Web 一致;多列时子项 `flex: 1` 或比例与 Web 列数一致。
- 完整检查项见 [reference.md - 视觉一致检查清单](reference.md#视觉一致检查清单);兼容映射见 [reference.md - Web→小程序 样式兼容映射表](reference.md#web小程序-样式兼容映射表)。
---
## 二、不能「配置化」的 UIAPI 控制)
以下均需**自定义组件/页面 + 请求同一套 API**,不能依赖 app.json 的静态配置。
### 2.1 底部导航
- **Tab 项动态显隐**(如按 `features.matchEnabled` 显示「找伙伴」):必须用**自定义底部栏**,在组件内请求配置接口,根据返回渲染项;跳转用 `wx.reLaunch` 等,不配置原生 tabBar。
- **按页面隐藏底部栏**:无 `usePathname()`,需按「当前页面路径」判断(各页是否渲染 BottomNav或在公共组件内维护不展示的页面列表
### 2.2 功能开关
- 找伙伴/推广/搜索/关于等若由后端 `feature_config` 控制:各页面/组件请求配置后按 `features.*` 条件渲染;小程序端与 Web 同一套逻辑,仅请求方式走适配层。
### 2.3 配置驱动的内容
- 匹配类型·次数·价格、书籍章节·价格、支付方式展示:凡从后端配置来的,均在**页面内请求接口再渲染**,不能写死在小程序配置里。
---
## 三、请求与域名
- **CORS**:小程序请求 API **不涉及 CORS**CORS 是浏览器策略);服务端无需为小程序加 CORS 头。
- **合法域名**:小程序必须在微信公众平台配置「请求合法域名」,否则 `wx.request``url not in domain list`;本地调试可设 `urlCheck: false`
- **baseURL**:小程序内需使用完整 API 地址(如 `https://soul.quwanzhi.com`),相对路径 `fetch('/api/xxx')` 会失败;适配层用 `getApp().globalData.baseUrl + path` 或等价方式。
---
## 四、路由与导航
- 所有跳转走**适配层**:小程序用 `wx.navigateTo` / `wx.reLaunch` / `wx.redirectTo` / `wx.navigateBack`Web 用 location/history不用 Next.js `Link` / `useRouter`
- 动态参数:`/read/[id]` 在小程序为 `/pages/read/read?id=xxx`,参数从 `getCurrentPages()[].options` 或适配层 `getPageQuery()` 获取。
- 底部 Tab 因使用自定义导航,用 `wx.reLaunch`,不用 `wx.switchTab`
---
## 五、存储与持久化
- **localStorage**:全部走适配层,小程序端用 `wx.getStorageSync` / `wx.setStorageSync`(如 match 页联系方式、匹配次数、自动提现配置等)。
- **Zustand persist**:需为 persist 提供自定义 storage小程序环境用 wx 的 storage否则登录态、设置等无法持久化。
---
## 六、登录与支付
- **微信登录**:若小程序用微信登录,走 `wx.login` 取 code 再调后端换 session与 Web 手机号/密码逻辑不同,需分支或适配。
- **支付**:小程序内用 `wx.requestPayment`;「展示哪些支付方式」仍可由现有 `settings.paymentMethods` 等 API 配置控制。
---
## 七、环境与 API 兼容
- **window / document**:使用前加 `if (!isMiniProgram())``window?.xxx`,避免报错。
- **URLSearchParams**:小程序不支持,需自实现 `buildQueryString` 或 polyfill。
- **标题**:用 `wx.setNavigationBarTitle`,不用 `document.title`
---
## 八、第三方库
- **framer-motion**Kbone 不支持,改用 CSS 动画或 `wx.createAnimation`,或移除动画。
- **Radix UI**:部分依赖 DOM/Portal小程序可能不可用用内联样式 + 自写组件替代Dialog、Tabs、Select 等)。
---
## 九、构建与包体
- 主包 ≤ 2MB总分包 ≤ 20MB必要时分包或减依赖。
- 中小项目建议 `splitChunks: false`,避免动态 chunk 缺失。
- Kbone 产出需与现有 miniprogram 壳合并custom-tab-bar、globalData、project.config 等)。
---
## 十、测试与发布
- 开发阶段可勾选「不校验合法域名」;体验版/真机须配置合法域名,且关闭 `urlCheck: false`
- 真机重点测:请求、支付、登录、存储、底部栏显隐、各功能开关。
---
## 参考
- **样式 1:1 迁移**[reference.md - Web→小程序 样式兼容映射表](reference.md#web小程序-样式兼容映射表)、[视觉一致检查清单](reference.md#视觉一致检查清单)、[补齐兼容实施步骤](reference.md#补齐兼容实施步骤1-1-样式迁移)。
- 完整转化清单与更多细节见 [reference.md](reference.md)。
- Kbone 配置与故障排查见 [../kbone-miniprogram/](../kbone-miniprogram/)。

View File

@@ -1,223 +0,0 @@
# Web 转小程序转化过程 - 详细清单
与 SKILL.md 配套使用,提供完整检查项与说明。**目标**:样式 1:1、100% 迁移,视觉与 Web 一致;有差异处做补齐兼容。
---
## Web→小程序 样式兼容映射表
| WebNext/CSS | 小程序能力 | 补齐兼容(视觉一致) |
|-----------------|------------|----------------------|
| `display: grid` / `grid-cols-N` | Grid 支持不完整 | 改为 `display: flex`,子项 `flex: 1``flex: 0 0 (100/N)%`**列数、间距与 Web 一致** |
| `gap: 12px` | 部分支持 gap | 用子项 `marginRight`/`marginBottom` 或父 padding**数值与 Web 一致**12px→24rpx 等) |
| `backdrop-filter` / `backdrop-blur-*` | 支持差/限制多 | 取 Web 背景主色 + 透明度:`backgroundColor: 'rgba(r,g,b,0.95)'`**视觉接近毛玻璃** |
| `position: sticky` | 不支持或仅组件 | `position: fixed` + 内容区 `paddingTop: 顶栏高度`**顶栏高度、背景与 Web 一致** |
| `box-shadow: 多值` | 仅单阴影 | 保留主阴影或 `border` + 单 `boxShadow`**颜色、模糊、偏移与 Web 主阴影一致** |
| `:hover` / `:last-child` 等伪类 | 不支持或部分 | 用 class/内联样式:如最后一项加 `marginBottom: 0`,其余统一 margin**间距数值一致** |
| `env(safe-area-inset-*)` | 支持 | 保留;确认构建后 WXSS 未丢失;`.safe-top`/`.safe-bottom` 等价实现,**数值一致** |
| `box-sizing: content-box`(默认) | Skyline 默认 border-box | 需与 Web 一致时配置 `defaultContentBox: true` 或显式设 `boxSizing: 'content-box'` |
| `rem` / `px` | rpx / rem | 统一基准750 宽→1px=2rpxrem 由 Kbone 转换;**换算后视觉一致** |
| oklch / 复杂颜色 | 部分支持 | 不支持的用 rgb/hex 替换,**色值一致** |
| 多 `background-image` | 仅单图 | 保留主图或合并为单图,**视觉近似** |
---
## 视觉一致检查清单
每页迁移后按下列项与 Web 并排对比,确保**肉眼无差异**。
### 全局
- [ ] 页面背景色与 Web 一致
- [ ] 安全区(顶部/底部/左右)与 Web 一致(有无留白、留白多少)
- [ ] 全局字体大小、行高、字重与 Web 一致
### 布局
- [ ] 多列数量与 Web 一致(如 4 列、3 列)
- [ ] 列间距、行间距与 Web 一致gap 或 margin 换算正确)
- [ ] 顶栏/底栏高度、内边距与 Web 一致
- [ ] 吸顶区域(若有)与 Web 视觉一致fixed + 占位)
### 组件与模块
- [ ] 卡片/列表项:圆角、内边距、边框、背景与 Web 一致
- [ ] 按钮:高度、圆角、字号、背景/边框与 Web 一致
- [ ] 图标+文字:垂直对齐、间距与 Web 一致lineHeight、alignItems
- [ ] 弹窗/遮罩:背景透明度、圆角与 Web 一致(毛玻璃→同色半透明)
### 文字与颜色
- [ ] 标题/正文字号、颜色、字重与 Web 一致
- [ ] 链接/强调色与 Web 一致
- [ ] 占位符、禁用态颜色与 Web 一致
### 阴影与装饰
- [ ] 主阴影(单阴影或近似)与 Web 主阴影颜色、模糊、偏移一致
- [ ] 装饰性 blur 可保留或简化,**不改变布局与主色**
### 验收通过标准
- 同一页面在 Web 与小程序并排对比,**字体、颜色、间距、圆角、对齐、安全区**无肉眼差异;有差异的已记录为「视觉等价替代」并符合上表。
---
## 补齐兼容实施步骤1:1 样式迁移)
1. **扫一遍 Web 样式**:列出所有 Grid、backdrop、sticky、多阴影、伪类间距、单位rem/px
2. **按映射表替换**:用 [Web→小程序 样式兼容映射表](#web小程序-样式兼容映射表) 逐项改为小程序等价写法,**数值与 Web 一致**单位换算750 宽下 1px≈2rpx
3. **必加属性**:有 padding/border 的容器加 `boxSizing: 'border-box'`;图标+文字处加 `lineHeight`;需占满的加 `width: '100%'``flex: 1`
4. **Skyline 若启用**:与 Web 不一致时配置 `defaultDisplayBlock``defaultContentBox`overflow 用 `scroll-view`sticky 用组件或 fixed+占位。
5. **验收**:按 [视觉一致检查清单](#视觉一致检查清单) 与 Web 并排对比,逐项打勾。
---
## 一、样式转化清单
### Grid 需改为 Flex 的典型位置(视觉等价)
- 首页「我的阅读」统计区grid-cols-4→ flex子项 flex: 1**4 列间距与 Web 一致**
- 我的页统计卡片、菜单区grid-cols-3→ flex子项 flex: 1**3 列间距一致**
- 找伙伴页统计/列表grid-cols-4→ 同上
- 弹窗内多列grid-cols-2 / grid-cols-3→ flex**列数、gap 一致**
- 目录/章节列表多列、书籍介绍多列 → flex**比例与间距一致**
- Dialog 居中:用 `display: flex; align-items: center; justify-content: center` 替代 `display: grid`**居中效果一致**
### 需替换或降级的样式(视觉等价补齐)
- `backdrop-blur-*`底部导航、顶栏、弹窗遮罩、glass-card → **取 Web 背景主色 + 透明度**(如 rgba(28,28,30,0.95)),视觉接近毛玻璃
- `position: sticky`:各页顶栏 → fixed + 内容区 paddingTop 占位,**顶栏高度、背景与 Web 一致**
- 装饰性 `blur-3xl` 等:可保留(对布局无影响);性能差再考虑简化,**不改变主色与布局**
- 多阴影:保留主阴影或单阴影+边框,**颜色、模糊与 Web 主阴影一致**
### 安全区
- `env(safe-area-inset-*)` 小程序支持;确认构建后 WXSS 中未丢失
- `.safe-top` / `.safe-bottom` 类需在小程序端有等价实现,**padding 数值与 Web 一致**
---
## 样式补充(联网核查)
以下基于微信官方 WXSS / Skyline 文档与社区实践整理,转化时可按需核对。
### WXSS 选择器
| 支持 | 不支持或部分支持 |
|------|-------------------|
| `.class``#id``element``element, element``::before``::after` | 通配 `*`、属性选择器 `[attr]` |
| Skyline 8.0.49+`:first-child``:last-child`8.0.50+`:nth-child``:not``:only-child``:empty` | 传统 WXSS 下伪类如 `:hover``:not()``:first-child` 等可能不支持,需以 JS 控制状态替代 |
- 依赖 `:last-child``:not()` 等做间距/边框时,改为给子项加 class 或内联样式(如 `marginRight``borderBottom`)。
### 单位与适配
- **rpx**:规定屏幕宽 750rpx设计稿 750px 可直接 1:1 转 rpx。竖屏布局、字体建议用 rpx避免 px 随系统字体缩放。
- **横屏**rpx 以宽度为基准,横屏会变;若支持横屏,可用 **vmin**(如 `100rpx ≈ 100vmin/7.5`)或动态计算。
- **rem**Kbone 可开 `global.rem: true`Tailwind 的 rem 会按小程序规范转换;与 rpx 二选一或统一策略。
### Skyline 渲染引擎差异(若启用)
- **默认值**`display: flex``box-sizing: border-box``flex-direction: column``position: relative`,与 Web 不同;布局错乱时可配置:
- `rendererOptions.skyline.defaultDisplayBlock: true` → 默认 block
- `rendererOptions.skyline.defaultContentBox: true` → 默认 content-box
- **不支持**:通配 `*`、属性选择器;`overflow: scroll`(用 `scroll-view`);单独 `overflow-x`/`overflow-y``position: sticky`(用 `sticky-header`/`sticky-section`inline / inline-block 布局(或仅 text 内部分支持)。
- **限制**`fixed` 的 top/left/bottom/right 不支持 `auto`z-index 无 Web 层叠上下文,只对兄弟节点生效;`box-shadow` 不支持多阴影叠加;`backdrop-filter` 不支持多函数、drop-shadow、url与 opacity 混用有问题blur 部分场景不一致SVG 不支持 rgba可用 fill-opacity。
- **Font-face**:仅支持 ttf。
### 内联样式与性能
- 官方建议:**静态样式写 class****style 只放动态样式**,避免全部塞进 style 影响解析与渲染。
- Kbone 若大量使用内联 style需权衡可把不变部分抽成 class动态部分再合并进 style。
### 动画
- CSS 动画transform、keyframes会拉高渲染开销宜少用、简化。
- Skyline 可用 Worklet 动画;传统 view 动画可用 `wx.createAnimation`
### Kbone 样式相关
- 尽量用 **HTML 标签**(如 `<input>``<img>`)而非小程序内置组件,减少包裹层对样式的影响。
- 用 webpack `DefinePlugin` 注入 `process.env.isMiniprogram`,便于样式与逻辑按端分支。
---
## 二、API 控制 UI 清单(不能配置化)
| 场景 | 当前实现 | 小程序做法 |
|------|----------|------------|
| 底部 Tab 数量与「找伙伴」显隐 | `/api/db/config``features.matchEnabled` | 自定义底部栏 + 同一配置接口 + `wx.reLaunch` |
| 按页面隐藏底部栏 | `usePathname()` 判断 | 按当前页面路径或各页是否挂载 BottomNav |
| 找伙伴/推广/搜索/关于开关 | `feature_config.*`(若接上) | 各页请求配置后条件渲染 |
| 匹配类型·次数·价格 | 可改为请求 `match_config` | 页面内请求并渲染 |
| 书籍章节·价格 | 可改为请求 `book_config`/`price_config` | 页面内请求并渲染 |
| 支付方式展示 | `settings.paymentMethods` | 同一配置,支付调起用 `wx.requestPayment` |
---
## 三、构建与配置清单
- [ ] miniprogram.config.jsrouter 每页单独配置,无 other 数组
- [ ] webpack entry 与 router 键名一致
- [ ] global.rem / pageStyle 按需开启
- [ ] 主包 ≤ 2MB必要时分包
- [ ] splitChunks中小项目建议 false
- [ ] 合并脚本dist/mp 与 miniprogram 壳合并custom-tab-bar、globalData、project.config
---
## 四、路由与导航清单
- [ ] 所有跳转走适配层navigateTo / reLaunch / redirectTo / navigateBack
- [ ] 底部 Tab 用 reLaunch因自定义导航
- [ ] 动态参数用 query/read/[id] → ?id=xxx从 getCurrentPages()[].options 或 getPageQuery() 取
- [ ] 无 usePathname按页面路径或各页挂载逻辑控制底部栏显隐
---
## 五、请求与域名清单
- [ ] 小程序不涉及 CORS服务端无需为小程序加 CORS 头
- [ ] 公众平台配置「请求合法域名」(如 https://soul.quwanzhi.com
- [ ] 请求 baseURL 为完整域名;适配层拼接 baseUrl + path
- [ ] 本地调试可 urlCheck: false发布前恢复并确认域名
---
## 六、存储与持久化清单
- [ ] 所有 localStorage 走适配层wx.getStorageSync / wx.setStorageSync
- [ ] Zustand persist 提供自定义 storage小程序用 wx storage
- [ ] match 页:联系方式、当日匹配次数等 key 在适配层统一实现
---
## 七、登录与支付清单
- [ ] 微信登录wx.login + code 换 session与 Web 逻辑分支或适配
- [ ] 支付:小程序内用 wx.requestPayment展示哪些方式仍由 API 配置控制
---
## 八、环境与 API 兼容清单
- [ ] window/document 使用前判断或可选链
- [ ] URLSearchParams 用自实现或 polyfill
- [ ] 页面标题用 wx.setNavigationBarTitle
---
## 九、第三方库清单
- [ ] framer-motion移除或改为 CSS / wx.createAnimation
- [ ] Radix UI用内联样式 + 自写组件替代Dialog、Tabs、Select 等)
- [ ] 其他依赖 DOM/BOM 的库:条件加载或替换
---
## 十、测试与发布清单
- [ ] 开发阶段:不校验合法域名可开启
- [ ] 体验版/真机合法域名已配置urlCheck 已关闭
- [ ] 真机验证:请求、支付、登录、存储、底部栏显隐、功能开关