design.md 3.7 KB

Context

清道夫微信小程序使用 navigationStyle: custom 实现自定义导航栏。所有页面顶部的标题、返回按钮、功能按钮(通知、新增、筛选等)都由组件自行渲染。然而微信小程序右上角存在系统胶囊按钮(菜单 + 关闭),在 iPhone 上宽度约 87px、安卓上约 96px,且距离屏幕右侧有一定边距。当前部分页面把操作按钮直接放在右上角,导致真机运行时胶囊遮挡按钮。

已有组件:StatusBar.vue 负责状态栏占位,TopBar.vue 负责标题栏。两者均未考虑胶囊区域。

Goals / Non-Goals

Goals:

  • 提供可在任何页面/组件复用的胶囊安全区方案。
  • 改造 TopBar.vue,使其右侧插槽内容自动避让胶囊。
  • 修复 pages/home/homepages/schedule/schedulepages/task/task 的遮挡问题。
  • 保持 H5/App 等非微信环境下的正常显示( graceful fallback)。

Non-Goals:

  • 不调整底部 tabBar 结构。
  • 不改页面整体布局风格。
  • 不处理胶囊以外的系统 UI(如灵动岛、底部横条)。

Decisions

1. 新增 CapsuleSafeArea.vue 组件

  • 通过 uni.getMenuButtonBoundingClientRect() 获取胶囊坐标与宽度。
  • 通过 uni.getSystemInfoSync() 获取屏幕宽度。
  • 计算右侧需要避让的最小宽度:screenWidth - menuButton.left + 8px(额外 8px 缓冲)。
  • 在微信小程序下渲染一个占位 view;在其他平台返回 0 或固定值,避免影响布局。
  • 提供 width 插槽 prop 或默认 slot,方便 TopBar 直接使用。

2. TopBar.vue 集成安全区

  • 右侧 <slot name="right" /> 外层用 CapsuleSafeArea 包裹,使右侧内容左侧平移。
  • 保持标题居左或根据左侧内容自适应,不改动标题样式。
  • 为避免标题被挤压过窄,标题区使用 flex-1 min-w-0 truncate

3. 页面顶部操作按钮统一使用 TopBar

  • pages/home/home 三个首页当前直接在页面内写 header,需把右上角通知铃铛移入 TopBar 的 right slot,或给按钮加 mr-[safeWidth]
  • pages/task/taskTaskListView 顶部「新增」按钮纳入 TopBar right slot。
  • pages/schedule/scheduleScheduleView 顶部「今天」「新增排班」按钮纳入 TopBar right slot。

4. 策略选择:右侧按钮整体左移

  • 对比方案:
    • 按钮换行:改动大,破坏视觉一致性。
    • 右侧留空白:浪费空间且用户看不到原因。
    • 按钮整体左移:改动最小,符合微信小程序主流做法,保留按钮可点击区域。
  • 选定「按钮整体左移」。

Risks / Trade-offs

  • [Risk] uni.getMenuButtonBoundingClientRect() 在小程序初始化后可能异步变化(如旋转屏幕)。
    • Mitigation:onMounted 获取并监听窗口尺寸变化;如获取失败则使用基于屏幕宽度的默认估算值。
  • [Risk] 不同机型胶囊尺寸差异大。
    • Mitigation: 使用动态 API 获取真实尺寸,而非写死 px。
  • [Risk] 顶部标题栏空间被压缩,标题可能显示不全。
    • Mitigation: 标题使用 truncate 截断,并确保左侧返回按钮只在需要时显示。
  • [Trade-off] H5/App 下无胶囊,安全区宽度为 0,布局与之前一致。

Migration Plan

  • 新增 CapsuleSafeArea.vue
  • 修改 TopBar.vue,集成安全区。
  • 修改三个页面/视图组件,使右上角按钮通过 TopBar right slot 渲染。
  • 构建 npm run build:mp-weixin 验证无编译错误。
  • 在微信开发者工具真机调试中检查胶囊未遮挡按钮。

Open Questions

  • 是否需要在每个页面单独处理 StatusBar + TopBar,还是统一封装一个 PageHeader?本次保持最小改动,只改 TopBar