跳转到内容

V5: 移动端 —— 「手机上也能用吗?」

出差的同事在微信群里吐槽:“手机上打开报销页面,按钮小得根本点不到,表格都挤在一起,每次都要放大缩小才能用。“老板顺手截图转发给你,加了一句”搞一下”。

你打开手机一看——确实,桌面端的三栏布局硬塞进 375px 宽的屏幕里,输入框要精确点击,下拉菜单被键盘挡住,日期选择器弹窗超出屏幕。这不是”改个样式”的事,是整个交互模式需要重新思考。

当前状态 (V4):系统已有完整的增删改查、JWT 鉴权、Redis 缓存、分页、乐观锁、事务、幂等。但前端只考虑了桌面浏览器。


层级问题影响
表象手机上按钮太小、表格溢出用户无法正常操作
直接原因CSS 使用固定宽度,未做响应式小屏幕布局崩溃
系统原因前端架构没有 mobile-first 设计所有组件都需要调整
设计缺失缺少移动端专属交互模式触摸操作不友好
根本原因没有考虑多端访问场景出差/外勤场景完全不可用
  • 触摸目标最小 44x44px(Apple HIG)/ 48x48dp(Material Design)
  • 移动端用户的核心操作:快速记一笔 > 查看列表 > 审批
  • 弱网环境(地铁/电梯)需要离线容错

graph TD
Phone["📱 手机"] --> API
PC["💻 电脑"] --> API
Tablet["📱 平板"] --> API
API["统一 REST API<br/>Go/Gin 后端"] --> Redis["Redis"]
API --> DB["PostgreSQL"]

关键变化:API 标准化 + 响应式前端 解决:手机/平板/电脑都能正常使用

决策点选项 A选项 B选择理由
技术路线开发独立 App响应式 Web + PWAB团队没有移动端开发经验,PWA 覆盖 90% 需求
CSS 策略桌面优先加 media queryMobile-first + Tailwind 断点BTailwind 默认就是 mobile-first
移动端导航顶部菜单折叠底部 Tab 栏B拇指热区友好,符合移动端习惯
表格展示横向滚动表格卡片式列表B卡片在小屏上信息密度更合理
快速记账跳转完整表单底部弹出简化表单B减少页面跳转,降低操作摩擦
前端改造(不涉及后端 API 变更):
├── Tailwind 响应式断点:sm(640) / md(768) / lg(1024)
├── 移动端布局:底部 Tab + 卡片列表 + 快速记账浮窗
├── PWA:manifest.json + service-worker(缓存静态资源)
└── 触摸优化:大按钮、滑动手势、防误触
  1. 全局布局响应式lg: 以上走桌面三栏,md: 以下切换为单栏 + 底部导航
  2. 列表页:桌面用表格,移动端用卡片(hidden lg:table / lg:hidden
  3. 快速记账:移动端首页常驻”+“按钮,弹出简化表单(金额 + 分类 + 备注)
  4. PWA manifest:支持”添加到主屏幕”,配置 display: standalone
  5. HTTP 缓存头:静态资源设置 Cache-Control,API 响应设置合理的缓存策略

我有一个 Go(Gin) + React + Tailwind CSS 的团队记账工具(报销管理系统)。
当前前端只适配了桌面端,需要做移动端适配。
技术栈:React 19 + Vite + Tailwind CSS v4 + React Router v7
请帮我完成以下改造:
1. **全局响应式布局**
- 桌面端(lg 以上):保持现有侧边栏 + 内容区布局
- 移动端(lg 以下):隐藏侧边栏,底部添加 Tab 导航栏(首页/列表/我的)
- Tab 栏高度 56px,图标 + 文字,当前页高亮
- 底部导航组件:BottomNav.jsx
2. **报销列表移动端卡片视图**
- 桌面端保持表格(加 class `hidden lg:block`)
- 移动端用卡片列表(加 class `lg:hidden`)
- 每张卡片显示:金额(大字)、分类标签、日期、状态徽章
- 卡片最小高度 72px,整个卡片可点击进详情
- 支持下拉刷新提示
3. **快速记账浮窗**
- 移动端右下角 FAB 按钮(56x56px,圆形,阴影)
- 点击弹出 bottom sheet(从底部滑出的半屏表单)
- 表单字段:金额(数字键盘)、分类(横向滚动标签选择)、备注(可选)
- 提交后自动关闭,显示 toast 成功提示
4. **触摸优化**
- 所有可点击元素最小 44x44px(用 Tailwind: `min-h-[44px] min-w-[44px]`)
- 按钮之间间距至少 8px
- 输入框高度 48px,字号 16px(防止 iOS 自动缩放)
- 表单 label 和 input 纵向排列(移动端不要横向并排)
5. **PWA 配置**
- 创建 public/manifest.json:name="团队记账",short_name="记账",
display="standalone",theme_color="#3B82F6"
- index.html 添加 manifest link 和 meta viewport
- 简单的 service worker:缓存 App Shell(HTML/CSS/JS)
6. **后端 HTTP 缓存头**(Go/Gin)
- 静态资源:`Cache-Control: public, max-age=31536000, immutable`(Vite 带 hash)
- API 响应:`Cache-Control: private, no-cache`(走 Redis 缓存即可)
- 添加 ETag 中间件用于静态资源
请给出完整的代码文件,保持与现有项目结构一致。

  • Chrome DevTools 切换到 iPhone SE(375px):布局不溢出,无横向滚动
  • 切换到 iPad(768px):合理利用空间,不过于拥挤
  • 桌面端(1024px+):保持原有布局不变
  • 底部 Tab 导航正常切换页面,当前页高亮
  • 快速记账浮窗弹出/收起动画流畅
  • 快速记账提交后列表自动刷新
  • 所有按钮手指可以轻松点击(不需要精确瞄准)
  • 输入框获得焦点时键盘不挡住当前输入
  • 下拉选择器在移动端可正常使用
  • iOS Safari 输入框不会触发页面自动缩放(字号 >= 16px)
  • lighthouse PWA 检测通过基本项
  • 浏览器显示”添加到主屏幕”提示
  • 从主屏幕打开无浏览器地址栏(standalone 模式)
  • 断网后 App Shell 可加载(静态资源已缓存)
  • 带 hash 的静态资源响应头包含 Cache-Control: public, max-age=31536000
  • API 响应头包含 Cache-Control: private, no-cache
  • 二次加载页面,静态资源走 disk cache(DevTools Network 查看)

主题对应模块
响应式设计不是”加 media query”,是重新思考交互模式→ Module 1 (API设计)
Mobile-first 意味着默认样式服务于最小屏幕→ Module 1
HTTP 缓存分层:浏览器缓存 → CDN → 应用缓存 → Redis→ Module 13 (HTTP缓存)
Cache-Control 的 public/private/no-cache/immutable 区别→ Module 13
PWA 是渐进增强,不是推翻重来→ Module 1
Service Worker 生命周期:install → activate → fetch→ Module 13

现象:点击输入框页面突然放大,用户迷惑。 原因:iOS Safari 对 font-size < 16px 的 input 会自动缩放。 解决:输入框字号设为 16px,或在 viewport meta 加 maximum-scale=1(不推荐,影响可访问性)。

2. 100vh 在移动端不等于可见高度

Section titled “2. 100vh 在移动端不等于可见高度”

现象:底部导航被浏览器工具栏挡住。 原因:移动浏览器的地址栏/工具栏占用空间但不算在 100vh 里。 解决:用 100dvh(dynamic viewport height)或 JS 计算 window.innerHeight

现象:网络慢时用户连点提交,创建了多条重复记录。 原因:移动端网络延迟更高,用户以为没反应。 解决:提交后立即 disable 按钮 + 显示 loading 态 + 后端幂等(V4 已有)。

现象:在某些设备上布局”半桌面半移动”很难看。 原因:断点设置不合理,或者在断点附近没有测试。 解决:用 Tailwind 默认断点(sm/md/lg/xl),重点测试 768px 附近的过渡。

现象:发布新版后用户看到的还是旧版。 原因:Service Worker 缓存了旧的 App Shell,没有更新策略。 解决:使用 stale-while-revalidate 策略,或在 SW 更新时提示用户刷新。