Files
Pawer/docs/taro-miniapp-design.md
2026-06-18 14:33:50 +08:00

25 KiB
Raw Permalink Blame History

汪圈 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所有 querySelectorclassListdataset 直接操作改为 React state 驱动。
  • pointerdown/pointermove/pointerup 改为 onTouchStart/onTouchMove/onTouchEnd
  • hover 效果改为 hoverClassactive 状态或点击反馈。
  • CSS 变量统一转 SCSS token减少不同基础库对 CSS custom properties 的兼容风险。

4. 小程序路由与页面

4.1 app.config.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 CustomNavBarSearchBarSegmentedTabsTopicChipsPostCardFeedAdCardLikeToastBottomTabBar 当前频道、话题、帖子列表、点赞状态、toast 显示 feedListpostLikepostFavorite
pages/nearby NearbyMapPetPinMapControlsLocationPillNearbySheetNearbyPetCardMatchToastBottomTabBar 选中宠物、Sheet 高度、筛选项、喜欢 toast nearbyPetslocationUpdatematchLike
pages/messages CustomNavBarSearchBarMessageTabsActiveUserRowConversationItemBottomTabBar 消息分类、会话列表、未读状态 messageListconversationRead
pages/profile ProfileHeroStatsRowActionButtonsPetShelfQuickGridPreferenceListBottomTabBar 用户资料、宠物列表、开关状态 profileGetprofileUpdatepetList
pages/publish PublishNavComposerAuthorComposerTextareaMediaGridTopicSelectorPublishOptionsComposerToolbarVisibilitySheetSuccessModal 文本、图片、话题、宠物、位置、可见范围、草稿 postCreatedraftSavepetList

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 classsetTimeout 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 keyframesView 伪元素改为子节点
Tab/Chip 选中 classList.toggle('act') React state 控制 activeKeyselectedIds
发布按钮启用 textarea input + disabled content.length > 0 && content.length <= 2000
开关滑块 .switch.off::after Switch 组件通过 checked class 驱动 knob 位移
图片删除 DOM remove mediaIds.filter() 更新列表
搜索区域点击缩放 直接写 style.transform pressed state + class180ms 后还原

注意:

  • 微信小程序不支持所有 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

$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 类型

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 宠物档案 ownerIdlocation
posts 动态内容 visibility + createdAtauthorId + createdAttopics
postLikes 点赞关系 postId + userId 唯一
postFavorites 收藏关系 postId + userId 唯一
comments 评论 postId + createdAt
locations 附近页定位快照 userIdgeo
matches 附近喜欢/匹配 fromUserId + toPetId
conversations 会话元信息 memberIdsupdatedAt
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 构建产物和云函数根目录:

{
  "miniprogramRoot": "dist/",
  "cloudfunctionRoot": "cloudfunctions/",
  "setting": {
    "urlCheck": true,
    "es6": true,
    "postcss": true,
    "minified": true
  }
}

src/app.tsx 中初始化云开发环境:

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.tsconfig/prod.ts.env,方便区分开发、测试和正式环境。

云函数目录采用单函数目录结构,便于微信开发者工具识别和单独部署:

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,统一封装:

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
}

服务分层:

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. 完整目录结构

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. 配置云开发环境 IDapp.tsx 中初始化 Taro.cloud.init({ env })
  4. 建立 styles/tokens.scssanimations.scss 和基础布局组件。

第 2 阶段:静态视觉还原

  1. 先迁移 plaza,抽出全局 PageShellCustomNavBarBottomTabBarPostCard
  2. 再迁移 messagesprofile复用头像、搜索、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. 先实现 loginfeedListprofileGet,让页面能加载真实用户态。
  2. 接入 postLikepostFavorite,验证计数幂等。
  3. 接入 postCreate 和媒体上传,发布后跳转广场并展示新动态。
  4. 接入 nearbyPetsmatchLikemessageListconversationRead
  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 云开发 APIhttps://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