袁宝工具箱:小程序卡片化首页的设计与实现
最近开发的小程序「袁宝工具箱」:首页没有固定布局,而是由 10 张功能卡片搭成的仪表盘——每张卡片都能显隐、排序,配置还带本地缓存与云端同步。这篇介绍卡片体系的功能点与实现思路。

卡片化首页
工具箱类小程序的通病是功能越加越多、首页九宫格越来越挤。我的做法是反过来:把首页做成一张可由用户自由编排的画布,每个功能是一张卡片,”用不用、排哪里”都交给用户。
技术底座是 uni-app(Vue3 + TypeScript)+ cool-uni 脚手架,一套代码同时跑微信小程序端。
目录结构
1 | |
十张功能卡片
| 卡片 | 功能点 |
|---|---|
| 🌍 人生进度 | “地球 Online 时间线”:填入生日,实时算出已活天数,在预期寿命进度条上定格。支持按年/按预期时间两种模式 |
| ⛅ 天气 | 当前天气 + 未来预报,城市可切换且选择持久化 |
| 📅 日历 | 翻月浏览、年月快速跳转(2000-2030),选中日期与其他卡片联动 |
| 🏮 农历信息 | 干支纪年 + 农历月日展示 |
| 📝 备忘录 | 数量角标 + 最近一次提醒摘要,支持农历提醒(按年滚动到下一年) |
| 👨👩👧 亲戚关系 | 亲戚关系计算器入口 |
| ➗ 算术练习 | 口算练习入口 |
| 📷 扫码助手 | 扫码工具入口 |
| 🚗 环中国游助手 | 沿边境环游中国的路线助手 |
| 🐦 鸟类科普 | 图鉴浏览,卡片角标展示分类总数(公开接口,无需登录) |
前三张(人生进度/天气/日历)是”信息型”卡片,直接在首页展开内容;后七张是”入口型”卡片,以图标 + 角标形式快速跳转。
功能点一:数据驱动的卡片渲染
首页没有 if-else 长列表,而是一份卡片清单驱动一切:
1 | |
每张卡片对应一份配置 { visible, order, config }:显示状态、排序权重、卡片私有配置(天气城市、生日、预期时间……)。首页模板只是一段 v-for="key in cardOrder",按 order 排序后逐个渲染:
1 | |
新增一张卡片 = 登记一行清单 + 写一个组件,渲染、排序、显隐、同步全部复用现有体系。
功能点二:长按拖拽排序
排序在”我的”页完成,拖拽是手写的(小程序没有好用的现成方案):
longpress触发,记录起始触点与当前卡片下标,进入拖拽态- 移动时计算触点偏移,实时映射到被拖卡片的
translate(dx, dy),其余卡片让位 - 松手后按最终位置重排
order,落位瞬间关闭transition再恢复,避免被拖项从旧偏移”滑”回列表的穿帮 - 拖拽激活时锁住页面滚动(
page-meta的overflow: hidden)
排序结果写回 order 权重,首页立即响应。
功能点三:配置的本地缓存 + 云端同步
这是整个卡片体系里最值得展开的部分。useCardConfig 是一个模块级单例 Composable,同时是”单一数据源”:
数据流
1 | |
- 首屏可用:先同步读本地缓存渲染,再异步拉远端
- 登录前后衔接:未登录只读本地;登录完成后
refreshFromRemote重新决策 - 防抖上行:本地变更 300ms 防抖后批量同步,避免高频写云端
冲突决策
本地和云端都有配置时怎么办?策略分四种:
| 本地 | 云端 | 行为 |
|---|---|---|
| 无 | 有 | 云端覆盖本地 |
| 有 | 无 | 本地推上云端(新账号首次登录) |
| 都有,内容一致 | 静默采用云端 | |
| 都有,内容不一致 | 弹窗让用户选:用云端 / 用本地(选本地则强制上行覆盖) |
两份配置比较前先做序列化排序(按 cardKey 排序后 JSON 比较),保证顺序无关的一致性判断。
两个容易踩的坑
remoteSynced的语义:拉到云端数据后置位,此后普通同步不再自动上行,防止旧本地数据覆盖云端。但用户主动改动(选城市、改生日)必须强制上行,所以setCardConfig/setCardVisible/setCardOrder都有forceSync参数——拉数据用的all接口读的正是这份最新缓存,下次进入才能拿到所选城市。- 旧缓存迁移:早期版本把排序和显隐散落在
card_order、card_visible_*等独立 storage key 里,新版读取时逐一识别并合并进新结构,老用户升级无感。
功能点四:备忘录卡片的”最近提醒”
备忘录卡片不只是数量角标,还要展示最近一次即将到来的提醒,这里有两个细节:
- 阴历提醒按年滚动:备忘录存的是阳历日期,阴历类型的提醒需要在客户端换算”今年的农历X月X日对应阳历几号”——后端旧逻辑用全局查找会把已过期的阴历提醒选上来,改为客户端从”开启提醒”的列表里挑”今天之后最近的一次”
- 跨页面共享单例:
useMemoCount是模块级单例,列表/详情页增删改后直接刷新同一份数据;首页则在onShow统一触发刷新,避免重复请求。文案也有讲究:提醒日期跨年时带上年份,避免用户误以为是今年已过期的日期
小结
卡片化首页的本质是**把”功能列表”抽象成”配置数据”**:
- 渲染由
CARD_KEYS+order+visible驱动,加功能不动首页 - 用户偏好(排序、显隐、卡片私有配置)统一收口到一个 Composable,本地与云端双写
- 信息型卡片(天气/日历/农历/人生进度)直接在首页出内容,入口型卡片做跳转,轻重搭配
后续加新功能,只需要”登记一行 + 写一个卡片组件 + (可选)在管理页加个图标”,整个体系自动接管剩下的工作。