744 lines
25 KiB
Markdown
744 lines
25 KiB
Markdown
# 汪圈 HTML 转 Taro 微信小程序设计文档
|
||
|
||
## 1. 背景与目标
|
||
|
||
当前参考稿位于 `refrence_html/`,共 6 个 HTML 文件:
|
||
|
||
| HTML 文件 | 目标页面 | 说明 |
|
||
| --- | --- | --- |
|
||
| `plaza.html` | `pages/plaza` | 广场信息流、搜索、频道 Tab、话题 Chip、点赞动效 |
|
||
| `nearby.html` | `pages/nearby` | 附近地图、宠物 Pin、可拖拽底部 Sheet、匹配喜欢动效 |
|
||
| `messages.html` | `pages/messages` | 消息页、活跃用户横滑、会话列表、未读状态 |
|
||
| `profile.html` | `pages/profile` | 我的页面、资料卡、宠物档案、偏好设置 |
|
||
| `publish.html` | `pages/publish` | 发布动态、图片网格、话题、可见范围 Sheet、发布成功弹层 |
|
||
| `wangquan-ios-launcher.html` | `pages/launcher`,可选 | 设计总览页,仅用于开发预览或品牌落地页,不进入主 Tab |
|
||
|
||
迁移目标:
|
||
|
||
1. 使用 Taro + React + TypeScript 构建微信小程序。
|
||
2. 保持参考 HTML 的内屏视觉、色彩、间距、圆角、阴影、字体层级和动效一致。
|
||
3. 适配微信小程序运行环境,使用自定义导航、真实安全区和微信胶囊位置。
|
||
4. 页面拆成可维护组件,避免把 HTML 直接平铺到单个页面。
|
||
5. 使用微信云开发模式:页面通过云函数访问业务数据,云数据库和云存储承载帖子、宠物、消息和媒体。
|
||
6. 输出可直接落地的目录结构、组件边界、云函数规划和迁移步骤。
|
||
|
||
## 2. 视觉一致性边界
|
||
|
||
参考 HTML 是桌面浏览器里的 iPhone 预览稿,包含 `stage-wrap`、`.phone`、刘海、状态栏、底部 home indicator 等展示壳。
|
||
|
||
小程序实现时采用以下边界:
|
||
|
||
- 保留 `.screen` 内的产品视觉:深紫背景、顶部内容、卡片、Tab、FAB、底部导航、Sheet、Toast、地图和发布页结构。
|
||
- 不把桌面预览用的外层 `.stage-wrap`、`.phone` 手机壳放进小程序页面,避免用户在微信里看到二次手机框。
|
||
- 使用 `navigationStyle: custom`,通过 `Taro.getSystemInfoSync()` 和 `Taro.getMenuButtonBoundingClientRect()` 计算状态栏、安全区和胶囊避让。
|
||
- 原 HTML 的 `status-bar` 抽象为 `CustomNavBar` 的安全区占位。正式小程序不模拟运营商、电量图标;视觉稿比对模式可通过 `VISUAL_PARITY_MODE` 开关显示模拟状态栏。
|
||
- 原 HTML 的 `home-indicator` 抽象为 `SafeAreaBottom`,在真机上优先使用系统安全区,视觉稿比对模式可显示白色横条。
|
||
|
||
## 3. 技术选型
|
||
|
||
| 层 | 选择 | 用途 |
|
||
| --- | --- | --- |
|
||
| 框架 | Taro 3.x/4.x | 编译到微信小程序 |
|
||
| UI | React + TypeScript | 页面和组件开发 |
|
||
| 样式 | SCSS + Taro pxTransform | 从 HTML CSS 迁移并统一设计 token |
|
||
| 状态 | React hooks + 轻量 store | 页面局部状态、用户会话、未读数量 |
|
||
| 数据 | 微信云开发云函数 + 云数据库 | Feed、宠物、消息、匹配、用户资料 |
|
||
| 媒体 | 云存储 | 图片、视频封面、头像 |
|
||
| 地图视觉 | CSS + 绝对定位,必要时 Canvas | 还原 `nearby.html` 的装饰地图 |
|
||
| 图标 | 原 SVG 路径资产化 | 统一转成 iconfont 或 PNG/SVG asset,避免直接依赖 Web SVG DOM |
|
||
|
||
关键约束:
|
||
|
||
- Taro 页面只能使用小程序支持的组件和样式能力,HTML 中的 `div/button/input/textarea/a` 需要迁移为 `View/Button/Input/Textarea/Navigator/Text/Image/ScrollView`。
|
||
- 小程序没有 DOM API,所有 `querySelector`、`classList`、`dataset` 直接操作改为 React state 驱动。
|
||
- `pointerdown/pointermove/pointerup` 改为 `onTouchStart/onTouchMove/onTouchEnd`。
|
||
- `hover` 效果改为 `hoverClass`、`active` 状态或点击反馈。
|
||
- CSS 变量统一转 SCSS token,减少不同基础库对 CSS custom properties 的兼容风险。
|
||
|
||
## 4. 小程序路由与页面
|
||
|
||
### 4.1 `app.config.ts`
|
||
|
||
```ts
|
||
export default defineAppConfig({
|
||
pages: [
|
||
'pages/plaza/index',
|
||
'pages/nearby/index',
|
||
'pages/publish/index',
|
||
'pages/messages/index',
|
||
'pages/profile/index'
|
||
],
|
||
window: {
|
||
navigationStyle: 'custom',
|
||
backgroundColor: '#14102b',
|
||
backgroundTextStyle: 'dark'
|
||
},
|
||
tabBar: {
|
||
custom: true,
|
||
color: '#8a7aab',
|
||
selectedColor: '#d8b4ff',
|
||
backgroundColor: '#14102b',
|
||
list: [
|
||
{ pagePath: 'pages/plaza/index', text: '广场' },
|
||
{ pagePath: 'pages/nearby/index', text: '附近' },
|
||
{ pagePath: 'pages/messages/index', text: '消息' },
|
||
{ pagePath: 'pages/profile/index', text: '我的' }
|
||
]
|
||
}
|
||
})
|
||
```
|
||
|
||
说明:
|
||
|
||
- `publish` 不是原生 tabBar 项,而是中间 FAB 跳转页。
|
||
- 使用自定义 `BottomTabBar` 实现 HTML 中间凸起发布按钮。
|
||
- `launcher` 可作为开发预览页放入 `subPackages/dev/pages/launcher`,不放入正式主包。
|
||
|
||
### 4.2 页面职责
|
||
|
||
| 页面 | 组件构成 | 主要状态 | 云函数 |
|
||
| --- | --- | --- | --- |
|
||
| `pages/plaza` | `CustomNavBar`、`SearchBar`、`SegmentedTabs`、`TopicChips`、`PostCard`、`FeedAdCard`、`LikeToast`、`BottomTabBar` | 当前频道、话题、帖子列表、点赞状态、toast 显示 | `feedList`、`postLike`、`postFavorite` |
|
||
| `pages/nearby` | `NearbyMap`、`PetPin`、`MapControls`、`LocationPill`、`NearbySheet`、`NearbyPetCard`、`MatchToast`、`BottomTabBar` | 选中宠物、Sheet 高度、筛选项、喜欢 toast | `nearbyPets`、`locationUpdate`、`matchLike` |
|
||
| `pages/messages` | `CustomNavBar`、`SearchBar`、`MessageTabs`、`ActiveUserRow`、`ConversationItem`、`BottomTabBar` | 消息分类、会话列表、未读状态 | `messageList`、`conversationRead` |
|
||
| `pages/profile` | `ProfileHero`、`StatsRow`、`ActionButtons`、`PetShelf`、`QuickGrid`、`PreferenceList`、`BottomTabBar` | 用户资料、宠物列表、开关状态 | `profileGet`、`profileUpdate`、`petList` |
|
||
| `pages/publish` | `PublishNav`、`ComposerAuthor`、`ComposerTextarea`、`MediaGrid`、`TopicSelector`、`PublishOptions`、`ComposerToolbar`、`VisibilitySheet`、`SuccessModal` | 文本、图片、话题、宠物、位置、可见范围、草稿 | `postCreate`、`draftSave`、`petList` |
|
||
|
||
## 5. 组件拆分
|
||
|
||
### 5.1 基础组件
|
||
|
||
| 组件 | 路径 | 说明 |
|
||
| --- | --- | --- |
|
||
| `PageShell` | `src/components/layout/PageShell` | 页面背景、滚动容器、安全区和底部留白 |
|
||
| `CustomNavBar` | `src/components/layout/CustomNavBar` | 自定义顶部栏,计算状态栏与胶囊避让 |
|
||
| `BottomTabBar` | `src/components/navigation/BottomTabBar` | 复刻 HTML 的底部 Tab 和中间发布 FAB |
|
||
| `Icon` | `src/components/ui/Icon` | 统一图标入口,映射原 SVG 到资产或 iconfont |
|
||
| `Avatar` | `src/components/ui/Avatar` | 渐变头像、在线点、宠物角标 |
|
||
| `Chip` | `src/components/ui/Chip` | 话题、筛选、标签选中态 |
|
||
| `SegmentedTabs` | `src/components/ui/SegmentedTabs` | 顶部频道切换和下划线 |
|
||
| `SearchBar` | `src/components/ui/SearchBar` | 搜索框视觉复用 |
|
||
| `ToastOverlay` | `src/components/feedback/ToastOverlay` | 点赞、匹配等居中放大 toast |
|
||
| `BottomSheet` | `src/components/feedback/BottomSheet` | 发布页可见范围选择、通用底部弹层 |
|
||
| `Switch` | `src/components/forms/Switch` | 复刻开关 knob 动效 |
|
||
|
||
### 5.2 业务组件
|
||
|
||
| 组件 | 路径 | 对应 HTML |
|
||
| --- | --- | --- |
|
||
| `PostCard` | `src/features/feed/components/PostCard` | `plaza.html` 的 `.post` |
|
||
| `FeedAdCard` | `src/features/feed/components/FeedAdCard` | `plaza.html` 的 `.ad-card` |
|
||
| `NearbyMap` | `src/features/nearby/components/NearbyMap` | `nearby.html` 的地图层、道路、水域、绿地 |
|
||
| `PetPin` | `src/features/nearby/components/PetPin` | `nearby.html` 的 `.pin` |
|
||
| `NearbySheet` | `src/features/nearby/components/NearbySheet` | `nearby.html` 的可拖拽 `.sheet` |
|
||
| `NearbyPetCard` | `src/features/nearby/components/NearbyPetCard` | `nearby.html` 的宠物卡片 |
|
||
| `ActiveUserRow` | `src/features/messages/components/ActiveUserRow` | `messages.html` 的活跃用户横向列表 |
|
||
| `ConversationItem` | `src/features/messages/components/ConversationItem` | `messages.html` 的 `.conv` |
|
||
| `ProfileHero` | `src/features/profile/components/ProfileHero` | `profile.html` 的 `.hero` |
|
||
| `PetShelf` | `src/features/profile/components/PetShelf` | `profile.html` 的毛孩子列表 |
|
||
| `PreferenceList` | `src/features/profile/components/PreferenceList` | `profile.html` 的设置列表 |
|
||
| `PublishComposer` | `src/features/publish/components/PublishComposer` | `publish.html` 的输入区 |
|
||
| `MediaGrid` | `src/features/publish/components/MediaGrid` | `publish.html` 的图片网格 |
|
||
| `PublishOptions` | `src/features/publish/components/PublishOptions` | `publish.html` 的关联宠物、位置、可见范围、草稿 |
|
||
| `ComposerToolbar` | `src/features/publish/components/ComposerToolbar` | `publish.html` 的底部工具栏 |
|
||
|
||
## 6. 动画与交互迁移方案
|
||
|
||
| 参考行为 | HTML 实现 | Taro 实现 |
|
||
| --- | --- | --- |
|
||
| 点赞爱心 toast | `.like-toast.show` + `scale` transition | `useToast()` 控制 `show` class,`setTimeout` 480ms 隐藏 |
|
||
| 附近匹配 toast | `.match-toast.show` | 复用 `ToastOverlay`,传入 `heart` 图标 |
|
||
| 发布页底部 Sheet | `@keyframes slideUp` | `BottomSheet` 使用 `animation: slideUp 280ms cubic-bezier(0.2, 0, 0, 1)` |
|
||
| 附近 Sheet 拖拽 | `pointer` 事件 + CSS 变量 `--sheet-h` | `useDragSheet` 用 touch 事件维护高度,snap 点按设计稿 60/220/420/620 px 等比转 rpx |
|
||
| 地图定位脉冲 | `@keyframes pulse` | 保留 WXSS keyframes,`View` 伪元素改为子节点 |
|
||
| Tab/Chip 选中 | `classList.toggle('act')` | React state 控制 `activeKey` 和 `selectedIds` |
|
||
| 发布按钮启用 | `textarea input` + disabled | `content.length > 0 && content.length <= 2000` |
|
||
| 开关滑块 | `.switch.off`、`::after` | `Switch` 组件通过 `checked` class 驱动 knob 位移 |
|
||
| 图片删除 | DOM remove | `mediaIds.filter()` 更新列表 |
|
||
| 搜索区域点击缩放 | 直接写 `style.transform` | `pressed` state + class,180ms 后还原 |
|
||
|
||
注意:
|
||
|
||
- 微信小程序不支持所有 Web 伪元素场景。复杂 `::before/::after` 需要改为显式 `View` 子节点,例如电池图标、地图 pulse、底部 home indicator。
|
||
- `position: sticky` 在发布页底部工具栏中改为 `position: fixed`,结合 `padding-bottom: env(safe-area-inset-bottom)` 避免被系统区域遮挡。
|
||
- `backdrop-filter` 兼容性需真机确认;无法完全稳定时,使用半透明背景 + 较高模糊感渐变替代。
|
||
|
||
## 7. 设计 Token
|
||
|
||
从 HTML 抽出统一 token,放入 `src/styles/tokens.scss`:
|
||
|
||
```scss
|
||
$bg: #14102b;
|
||
$bg-warm: #1c1442;
|
||
$surface: #1f1742;
|
||
$surface-2: #251c4a;
|
||
$surface-hi: #2d2255;
|
||
$fg: #f0e9ff;
|
||
$fg-2: #c7b9e0;
|
||
$muted: #8a7aab;
|
||
$border: #2e234a;
|
||
$border-soft: #251c40;
|
||
$accent: #d8b4ff;
|
||
$accent-2: #ffb3c8;
|
||
$primary: #ffd9a8;
|
||
$primary-on: #2a1d10;
|
||
$success: #8fe5b5;
|
||
$warn: #ffd166;
|
||
$danger: #ff8a9b;
|
||
$map-bg: #0e0a22;
|
||
|
||
$font-display: "Space Grotesk", "Inter", system-ui, sans-serif;
|
||
$font-body: "Inter", system-ui, -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif;
|
||
|
||
$radius-sm: 10px;
|
||
$radius-md: 16px;
|
||
$radius-lg: 24px;
|
||
$radius-pill: 9999px;
|
||
```
|
||
|
||
迁移策略:
|
||
|
||
- 原样保留色值、透明度、渐变角度和阴影参数。
|
||
- Taro 构建配置按 390px 参考宽度做 px 到 rpx 的转换;如果当前 Taro 版本对自定义 `designWidth: 390` 支持不理想,则用 750 基准并执行 `750 / 390` 的机械转换。
|
||
- 字体在微信里不能稳定加载 Google Fonts。正式版以系统字体 + `PingFang SC` 为准;若必须完全还原 `Space Grotesk/Inter`,将字体文件放入云存储或本地资产并通过 `Taro.loadFontFace` 加载。
|
||
|
||
## 8. 数据模型
|
||
|
||
### 8.1 TypeScript 类型
|
||
|
||
```ts
|
||
export interface UserProfile {
|
||
_id: string
|
||
openid: string
|
||
nickname: string
|
||
avatarUrl?: string
|
||
location?: string
|
||
yearsWithPets?: number
|
||
level: number
|
||
stats: {
|
||
posts: number
|
||
following: number
|
||
followers: number
|
||
favorites: number
|
||
}
|
||
preferences: {
|
||
notifications: boolean
|
||
nearbyVisible: boolean
|
||
}
|
||
}
|
||
|
||
export interface Pet {
|
||
_id: string
|
||
ownerId: string
|
||
name: string
|
||
species: 'dog' | 'cat' | 'other'
|
||
breed: string
|
||
ageText: string
|
||
avatarFileId?: string
|
||
tags: string[]
|
||
location?: GeoPoint
|
||
online?: boolean
|
||
}
|
||
|
||
export interface Post {
|
||
_id: string
|
||
authorId: string
|
||
petId?: string
|
||
content: string
|
||
topics: string[]
|
||
media: MediaAsset[]
|
||
locationText?: string
|
||
visibility: 'public' | 'friends' | 'private'
|
||
counts: {
|
||
likes: number
|
||
comments: number
|
||
shares: number
|
||
favorites: number
|
||
}
|
||
likedByMe?: boolean
|
||
favoritedByMe?: boolean
|
||
createdAt: number
|
||
}
|
||
|
||
export interface Conversation {
|
||
_id: string
|
||
type: 'single' | 'group' | 'system'
|
||
title: string
|
||
avatarKey?: string
|
||
preview: string
|
||
unreadCount: number
|
||
pinned?: boolean
|
||
muted?: boolean
|
||
updatedAt: number
|
||
}
|
||
```
|
||
|
||
### 8.2 云数据库集合
|
||
|
||
| 集合 | 用途 | 关键索引 |
|
||
| --- | --- | --- |
|
||
| `users` | 用户基础资料、偏好、统计 | `openid` 唯一 |
|
||
| `pets` | 宠物档案 | `ownerId`、`location` |
|
||
| `posts` | 动态内容 | `visibility + createdAt`、`authorId + createdAt`、`topics` |
|
||
| `postLikes` | 点赞关系 | `postId + userId` 唯一 |
|
||
| `postFavorites` | 收藏关系 | `postId + userId` 唯一 |
|
||
| `comments` | 评论 | `postId + createdAt` |
|
||
| `locations` | 附近页定位快照 | `userId`、`geo` |
|
||
| `matches` | 附近喜欢/匹配 | `fromUserId + toPetId` |
|
||
| `conversations` | 会话元信息 | `memberIds`、`updatedAt` |
|
||
| `messages` | 消息内容 | `conversationId + createdAt` |
|
||
| `notifications` | 系统通知 | `userId + read + createdAt` |
|
||
| `drafts` | 发布草稿 | `userId + updatedAt` |
|
||
|
||
## 9. 云函数设计
|
||
|
||
统一入口原则:
|
||
|
||
- 小程序端通过 `Taro.cloud.callFunction` 调用云函数。
|
||
- 除云存储上传文件外,业务写操作都走云函数,云函数内校验 `openid`、参数、权限和数据归属。
|
||
- 查询函数返回页面所需 DTO,减少小程序端多次拼接请求。
|
||
- 点赞、收藏、计数更新在云函数内用事务或幂等逻辑完成。
|
||
|
||
| 云函数 | 入参 | 出参 | 说明 |
|
||
| --- | --- | --- | --- |
|
||
| `login` | `{ userInfo? }` | `{ openid, user }` | 获取 openid,初始化或更新用户 |
|
||
| `feedList` | `{ channel, topic?, cursor?, pageSize }` | `{ list, nextCursor }` | 广场/关注/附近信息流 |
|
||
| `postCreate` | `{ content, topics, media, petId?, location?, visibility }` | `{ postId }` | 发布动态并更新统计 |
|
||
| `postLike` | `{ postId, liked }` | `{ liked, likes }` | 幂等点赞/取消点赞 |
|
||
| `postFavorite` | `{ postId, favorited }` | `{ favorited, favorites }` | 幂等收藏 |
|
||
| `draftSave` | `{ draft }` | `{ draftId, updatedAt }` | 保存发布草稿 |
|
||
| `nearbyPets` | `{ location, filters }` | `{ list }` | 附近宠物列表和地图 pin |
|
||
| `locationUpdate` | `{ location, visible }` | `{ ok }` | 更新自己的附近可见状态 |
|
||
| `matchLike` | `{ petId }` | `{ matched }` | 附近页喜欢/匹配 |
|
||
| `messageList` | `{ tab, cursor? }` | `{ activeUsers, conversations, nextCursor }` | 消息页聚合数据 |
|
||
| `conversationRead` | `{ conversationId }` | `{ unreadCount }` | 标记会话已读 |
|
||
| `profileGet` | `{ userId? }` | `{ user, pets }` | 获取我的/他人资料 |
|
||
| `profileUpdate` | `{ patch }` | `{ user }` | 更新资料和偏好 |
|
||
| `petList` | `{ ownerId? }` | `{ list }` | 宠物列表 |
|
||
| `petSave` | `{ pet }` | `{ petId }` | 创建或更新宠物 |
|
||
|
||
### 9.1 云开发工程配置
|
||
|
||
`project.config.json` 需要显式声明 Taro 构建产物和云函数根目录:
|
||
|
||
```json
|
||
{
|
||
"miniprogramRoot": "dist/",
|
||
"cloudfunctionRoot": "cloudfunctions/",
|
||
"setting": {
|
||
"urlCheck": true,
|
||
"es6": true,
|
||
"postcss": true,
|
||
"minified": true
|
||
}
|
||
}
|
||
```
|
||
|
||
`src/app.tsx` 中初始化云开发环境:
|
||
|
||
```ts
|
||
import Taro from '@tarojs/taro'
|
||
|
||
const cloudEnv = process.env.TARO_APP_CLOUD_ENV
|
||
|
||
if (process.env.TARO_ENV === 'weapp' && cloudEnv) {
|
||
Taro.cloud.init({
|
||
env: cloudEnv,
|
||
traceUser: true
|
||
})
|
||
}
|
||
```
|
||
|
||
环境 ID 不写死在页面代码里,放到 `config/dev.ts`、`config/prod.ts` 或 `.env`,方便区分开发、测试和正式环境。
|
||
|
||
云函数目录采用单函数目录结构,便于微信开发者工具识别和单独部署:
|
||
|
||
```text
|
||
cloudfunctions/
|
||
login/
|
||
index.ts
|
||
package.json
|
||
feedList/
|
||
index.ts
|
||
package.json
|
||
postCreate/
|
||
index.ts
|
||
package.json
|
||
postLike/
|
||
index.ts
|
||
package.json
|
||
postFavorite/
|
||
index.ts
|
||
package.json
|
||
draftSave/
|
||
index.ts
|
||
package.json
|
||
nearbyPets/
|
||
index.ts
|
||
package.json
|
||
locationUpdate/
|
||
index.ts
|
||
package.json
|
||
matchLike/
|
||
index.ts
|
||
package.json
|
||
messageList/
|
||
index.ts
|
||
package.json
|
||
conversationRead/
|
||
index.ts
|
||
package.json
|
||
profileGet/
|
||
index.ts
|
||
package.json
|
||
profileUpdate/
|
||
index.ts
|
||
package.json
|
||
petList/
|
||
index.ts
|
||
package.json
|
||
petSave/
|
||
index.ts
|
||
package.json
|
||
```
|
||
|
||
## 10. 客户端服务层
|
||
|
||
客户端不在页面里直接散落 `callFunction`,统一封装:
|
||
|
||
```ts
|
||
export async function callCloud<TReq extends object, TRes>(
|
||
name: CloudFunctionName,
|
||
data: TReq
|
||
): Promise<TRes> {
|
||
const res = await Taro.cloud.callFunction({ name, data })
|
||
return res.result as TRes
|
||
}
|
||
```
|
||
|
||
服务分层:
|
||
|
||
```text
|
||
src/services/
|
||
cloud.ts # callCloud、错误归一化、loading guard
|
||
auth.service.ts # login
|
||
feed.service.ts # feedList/postLike/postFavorite
|
||
publish.service.ts # postCreate/draftSave/uploadMedia
|
||
nearby.service.ts # nearbyPets/locationUpdate/matchLike
|
||
message.service.ts # messageList/conversationRead
|
||
profile.service.ts # profileGet/profileUpdate/petList/petSave
|
||
```
|
||
|
||
页面只依赖 service 和 hooks,不直接依赖云函数细节。
|
||
|
||
## 11. 完整目录结构
|
||
|
||
```text
|
||
Pet/
|
||
project.config.json
|
||
project.private.config.json
|
||
package.json
|
||
tsconfig.json
|
||
config/
|
||
index.ts
|
||
dev.ts
|
||
prod.ts
|
||
src/
|
||
app.config.ts
|
||
app.scss
|
||
app.tsx
|
||
assets/
|
||
icons/
|
||
compass.svg
|
||
heart.svg
|
||
message.svg
|
||
plus.svg
|
||
user.svg
|
||
search.svg
|
||
map-pin.svg
|
||
more.svg
|
||
close.svg
|
||
images/
|
||
README.md
|
||
components/
|
||
layout/
|
||
PageShell/
|
||
index.tsx
|
||
index.scss
|
||
CustomNavBar/
|
||
index.tsx
|
||
index.scss
|
||
SafeAreaBottom/
|
||
index.tsx
|
||
index.scss
|
||
navigation/
|
||
BottomTabBar/
|
||
index.tsx
|
||
index.scss
|
||
tabConfig.ts
|
||
ui/
|
||
Avatar/
|
||
index.tsx
|
||
index.scss
|
||
Chip/
|
||
index.tsx
|
||
index.scss
|
||
Icon/
|
||
index.tsx
|
||
iconMap.ts
|
||
index.scss
|
||
SearchBar/
|
||
index.tsx
|
||
index.scss
|
||
SegmentedTabs/
|
||
index.tsx
|
||
index.scss
|
||
Switch/
|
||
index.tsx
|
||
index.scss
|
||
feedback/
|
||
BottomSheet/
|
||
index.tsx
|
||
index.scss
|
||
ToastOverlay/
|
||
index.tsx
|
||
index.scss
|
||
features/
|
||
feed/
|
||
components/
|
||
FeedAdCard/
|
||
index.tsx
|
||
index.scss
|
||
PostCard/
|
||
index.tsx
|
||
index.scss
|
||
feed.types.ts
|
||
nearby/
|
||
components/
|
||
MapControls/
|
||
index.tsx
|
||
index.scss
|
||
NearbyMap/
|
||
index.tsx
|
||
index.scss
|
||
NearbyPetCard/
|
||
index.tsx
|
||
index.scss
|
||
NearbySheet/
|
||
index.tsx
|
||
index.scss
|
||
PetPin/
|
||
index.tsx
|
||
index.scss
|
||
nearby.types.ts
|
||
messages/
|
||
components/
|
||
ActiveUserRow/
|
||
index.tsx
|
||
index.scss
|
||
ConversationItem/
|
||
index.tsx
|
||
index.scss
|
||
message.types.ts
|
||
profile/
|
||
components/
|
||
PetShelf/
|
||
index.tsx
|
||
index.scss
|
||
PreferenceList/
|
||
index.tsx
|
||
index.scss
|
||
ProfileHero/
|
||
index.tsx
|
||
index.scss
|
||
QuickGrid/
|
||
index.tsx
|
||
index.scss
|
||
StatsRow/
|
||
index.tsx
|
||
index.scss
|
||
profile.types.ts
|
||
publish/
|
||
components/
|
||
ComposerToolbar/
|
||
index.tsx
|
||
index.scss
|
||
MediaGrid/
|
||
index.tsx
|
||
index.scss
|
||
PublishComposer/
|
||
index.tsx
|
||
index.scss
|
||
PublishOptions/
|
||
index.tsx
|
||
index.scss
|
||
VisibilitySheet/
|
||
index.tsx
|
||
index.scss
|
||
SuccessModal/
|
||
index.tsx
|
||
index.scss
|
||
publish.types.ts
|
||
hooks/
|
||
useCloudQuery.ts
|
||
useDragSheet.ts
|
||
useSystemLayout.ts
|
||
useToast.ts
|
||
useUploadMedia.ts
|
||
pages/
|
||
plaza/
|
||
index.config.ts
|
||
index.tsx
|
||
index.scss
|
||
nearby/
|
||
index.config.ts
|
||
index.tsx
|
||
index.scss
|
||
publish/
|
||
index.config.ts
|
||
index.tsx
|
||
index.scss
|
||
messages/
|
||
index.config.ts
|
||
index.tsx
|
||
index.scss
|
||
profile/
|
||
index.config.ts
|
||
index.tsx
|
||
index.scss
|
||
services/
|
||
auth.service.ts
|
||
cloud.ts
|
||
feed.service.ts
|
||
message.service.ts
|
||
nearby.service.ts
|
||
profile.service.ts
|
||
publish.service.ts
|
||
store/
|
||
session.store.ts
|
||
ui.store.ts
|
||
styles/
|
||
animations.scss
|
||
mixins.scss
|
||
tokens.scss
|
||
utilities.scss
|
||
types/
|
||
cloud.ts
|
||
domain.ts
|
||
global.d.ts
|
||
utils/
|
||
date.ts
|
||
px.ts
|
||
validators.ts
|
||
cloudfunctions/
|
||
login/
|
||
index.ts
|
||
package.json
|
||
feedList/
|
||
index.ts
|
||
package.json
|
||
postCreate/
|
||
index.ts
|
||
package.json
|
||
postLike/
|
||
index.ts
|
||
package.json
|
||
postFavorite/
|
||
index.ts
|
||
package.json
|
||
draftSave/
|
||
index.ts
|
||
package.json
|
||
nearbyPets/
|
||
index.ts
|
||
package.json
|
||
locationUpdate/
|
||
index.ts
|
||
package.json
|
||
matchLike/
|
||
index.ts
|
||
package.json
|
||
messageList/
|
||
index.ts
|
||
package.json
|
||
conversationRead/
|
||
index.ts
|
||
package.json
|
||
profileGet/
|
||
index.ts
|
||
package.json
|
||
profileUpdate/
|
||
index.ts
|
||
package.json
|
||
petList/
|
||
index.ts
|
||
package.json
|
||
petSave/
|
||
index.ts
|
||
package.json
|
||
docs/
|
||
taro-miniapp-design.md
|
||
refrence_html/
|
||
messages.html
|
||
nearby.html
|
||
plaza.html
|
||
profile.html
|
||
publish.html
|
||
wangquan-ios-launcher.html
|
||
```
|
||
|
||
## 12. 迁移步骤
|
||
|
||
### 第 1 阶段:工程初始化
|
||
|
||
1. 使用 Taro React TypeScript 模板初始化项目。
|
||
2. 配置微信小程序编译、`navigationStyle: custom`、自定义 tabBar。
|
||
3. 配置云开发环境 ID,`app.tsx` 中初始化 `Taro.cloud.init({ env })`。
|
||
4. 建立 `styles/tokens.scss`、`animations.scss` 和基础布局组件。
|
||
|
||
### 第 2 阶段:静态视觉还原
|
||
|
||
1. 先迁移 `plaza`,抽出全局 `PageShell`、`CustomNavBar`、`BottomTabBar`、`PostCard`。
|
||
2. 再迁移 `messages` 和 `profile`,复用头像、搜索、tab、switch。
|
||
3. 迁移 `publish`,重点处理 `Textarea`、底部 fixed toolbar、Sheet 和成功弹层。
|
||
4. 迁移 `nearby`,重点处理地图层、pin 布局、底部拖拽 Sheet。
|
||
|
||
### 第 3 阶段:交互和动画
|
||
|
||
1. 全部 DOM 操作替换为 state。
|
||
2. 完整还原点赞 toast、匹配 toast、Sheet slideUp、地图 pulse、switch knob、FAB active。
|
||
3. 用微信开发者工具和真机分别确认 `backdrop-filter`、fixed 底部、safe-area、键盘弹起表现。
|
||
|
||
### 第 4 阶段:云函数接入
|
||
|
||
1. 先实现 `login`、`feedList`、`profileGet`,让页面能加载真实用户态。
|
||
2. 接入 `postLike`、`postFavorite`,验证计数幂等。
|
||
3. 接入 `postCreate` 和媒体上传,发布后跳转广场并展示新动态。
|
||
4. 接入 `nearbyPets`、`matchLike`、`messageList`、`conversationRead`。
|
||
5. 补充数据库权限规则:客户端默认只读必要公开数据,写入走云函数。
|
||
|
||
### 第 5 阶段:验收
|
||
|
||
1. 与参考 HTML 做逐页截图对比,基准宽度 390px。
|
||
2. 检查 320/375/390/414 宽度下内容不重叠、不溢出。
|
||
3. 真机检查 iPhone 刘海屏、普通屏、安卓微信的状态栏、胶囊和底部安全区。
|
||
4. 云函数使用测试环境数据跑通发布、点赞、匹配、消息已读、资料更新。
|
||
|
||
## 13. 风险与处理
|
||
|
||
| 风险 | 影响 | 处理 |
|
||
| --- | --- | --- |
|
||
| HTML 使用大量 inline SVG | 微信小程序无法像 Web 一样直接渲染全部 SVG DOM | 将图标资产化为 iconfont 或图片资产;地图 SVG 改为 CSS/Canvas 组合 |
|
||
| Google Fonts 不可直接加载 | 字体观感略有差异 | 本地/云存储加载字体,或确认系统字体可接受 |
|
||
| `backdrop-filter` 兼容性 | 玻璃模糊效果可能变弱 | 半透明深色背景 + 渐变阴影兜底 |
|
||
| `position: sticky`/伪元素差异 | 发布页底部栏和装饰元素偏移 | fixed + safe area;伪元素改显式节点 |
|
||
| 附近页拖拽性能 | touch move 频繁 setState 可能卡顿 | 用 `useRef` 缓存拖拽值,必要时节流,最终 snap 时 setState |
|
||
| 视觉 100% 与真实小程序系统 UI 冲突 | 状态栏/胶囊不可完全控制 | 明确只对产品内屏做 100% 还原;系统区域用真实安全区适配 |
|
||
|
||
## 14. 参考文档
|
||
|
||
- Taro 官方文档:`https://docs.taro.zone/`
|
||
- Taro 云开发 API:`https://docs.taro.zone/docs/apis/cloud/`
|
||
- 微信小程序云开发文档:`https://developers.weixin.qq.com/miniprogram/dev/wxcloud/basis/getting-started.html`
|
||
- 微信云函数调用:`https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-sdk-api/functions/callFunction/client.callFunction.html`
|