最近做了一个微信小程序项目 foodie-footprint,想把"吃过什么、花了多少、值不值得再来"这件事记录下来。项目不算复杂,但在实现过程中把登录鉴权、打卡记录、图片上传、位置选择、地图足迹、收藏体系和消费统计这些典型能力基本都跑通了。
这篇文章就结合当前项目,聊聊这个小程序从 0 到 1 的实现思路,以及几个我觉得比较值得记录下来的技术细节。
01. 这个项目是怎么冒出来的
这个小程序叫 foodie-footprint,我自己给它起的中文名是"干饭足迹"。
一开始想做它,原因不复杂,甚至有点过于普通了。
就是那种很常见的时刻:吃到一家店,觉得"不错,下次再来",过两周名字忘了;或者总觉得自己最近也没怎么花钱,结果一翻账单,奶茶、咖啡、简餐、夜宵全算上,数字相当诚实。
我后来发现,和"吃饭"有关的记忆其实特别容易散。你会记得某一顿当下很开心,但不太会系统地记住:
- 这家店到底叫什么
- 我花了多少钱
- 它在哪
- 我到底还想不想再去
所以我就想,干脆做个小程序,把这些事情认真记下来。
最开始我以为它会是个很轻的小东西,结果越做越不像"一个表单页",慢慢长成了一个完整项目:
- 微信登录
- 打卡记录
- 图片上传
- 地点选择
- 地图足迹
- 收藏店铺
- 消费报告
- 成就勋章
它不是一个多大的系统,但它确实已经有了点"像产品"的样子。
02. 我没用很重的技术栈
这个项目的技术选型挺老实的,没有故意上难度:
- 微信小程序原生框架
tdesign-miniprogramqiun-data-charts- 微信云开发
- 云数据库
- 云存储
为什么这么选?
因为这种项目最怕一上来就把自己埋进技术栈里,页面还没跑通,架构先讲半天。对我来说,这个项目最重要的是先把"记录吃饭"这件事做顺,再考虑怎么做得更好看、更完整。
原生小程序 + 云开发这套东西,有个很实际的好处:你离运行环境很近,很多事情不需要绕。
尤其是地图、登录、云函数、文件上传这种能力,越贴近平台,越省心。
03. 表面上是 12 个页面,本质上是在做一条顺滑的使用路径
这个项目现在有这些页面:
- 首页
- 登录页
- 打卡页
- 地图页
- 收藏页
- 记录页
- 详情页
- 报告页
- 我的页面
- 成就页
- 资料编辑页
- 反馈页
看起来页面很多,但真正麻烦的其实不是页面数量,而是这些页面之间怎么接。
我做这类项目的时候,最怕一种状态:每个页面单看都还行,但连起来特别拧巴。
比如:
- 没登录时,是直接拦,还是先让你看看
- 打完卡以后,首页要不要马上更新
- 从地图页去补记录,最后应该回哪里
- 收藏和记录之间,到底该怎么关联
这些问题每个都不大,但只要处理得糙一点,整个项目就会看起来很散。
后来我越来越觉得,一个项目"像不像真的会有人用",往往就看这些地方。
04. 首页最怕做成"几个数字摆在那儿"
很多练手项目的首页都会有一个问题:它不是首页,它只是一个入口板。
放几个统计数字,再放几个按钮,乍一看挺完整,实际上没什么承接能力。
我这个项目里,首页主要做两件事:
- 展示累计打卡次数和累计消费金额
- 展示最近的打卡时间线
对应的逻辑也很直接:
getStats拉统计getRecords拉记录列表
但真正让我花心思的,不是"怎么显示",而是"更新之后怎么办"。
因为这不是一个纯展示项目。用户会新增记录、编辑记录、删除记录。如果每次操作完都粗暴地整页重拉,虽然也能用,但体验很硬,像一块没磨过边的板子。
所以我后面补了一层本地同步逻辑。简单讲,就是某些数据先在本地做轻量更新,等页面真的回来了,再决定要不要全量刷新。
这个设计不算多高深,但它很值。因为用户感受到的不是"这里做了同步优化",而是"这个项目反应挺顺"。
05. 打卡页看着像表单,实际上是项目里最啰嗦的一页
如果只从 UI 看,打卡页无非就是填内容、传图片、点提交。
但真正做起来,它其实特别碎。
要处理的东西有:
- 店名
- 金额
- 分类
- 标签
- 时间
- 评分
- 备注
- 图片
- 地点
而且还不只是新增,还得支持编辑。
新增和编辑,我最后没拆成两页
我一开始也想过,新增一页,编辑一页,看起来很清楚。
后来想明白了,没必要。
这两种场景的主体逻辑几乎是同一套:图片上传、金额输入、分类标签、时间选择、地点选择,全都一样。硬拆成两页,除了让自己后面维护更烦,没什么实际收益。
所以最后就是一个 add 页,两种模式切换。
这种取舍我后来越来越常做:如果两个页面八成一样,那就别为了"形式上分开"硬拆。
图片上传这件事,最怕"功能有了,体验没了"
图片上传很容易写成"能传就行",但真上手一试就知道不够。
原图一大,问题就来了:
- 上传慢
- 等待感重
- 网络差的时候很容易卡住
所以我在前端加了一层压缩判断。图片大于阈值,就先压一下,再传云存储。
这个动作本身不稀奇,但很必要。因为记录、详情、收藏这些页面最后都会吃到图片。如果源头不收一下,后面全都要跟着受罪。
位置选择不是调个 API 就结束
一开始我真以为 chooseLocation 调起来就完了。
结果一写才发现,前面还有一串现实问题:
- 用户有没有授权位置权限
- 拒绝过以后怎么处理
- 已经有位置时,要不要拿它做默认点
- 用户取消选点,要不要提示
这些逻辑都不难,但很容易偷懒。如果偷懒,项目不会立刻坏,只是会给人一种不太稳的感觉。
我现在做项目越来越信一个判断:很多"产品感差一点"的地方,本质上就是这些小事没处理。
06. 地图页是我做着做着开始上头的一块
我本来对地图页的预期很简单:把吃过的店标到地图上,看看自己都在哪吃过饭。
后来做到一半,我突然觉得,如果它只是"展示足迹",那有点浪费。
既然已经有位置数据了,不如干脆把它做成一个能继续帮我找店的页面。
于是我往里面继续加:
- 分类筛选
- 关键词搜索
- 距离最近排序
- 只看收藏
- marker 和底部卡片联动
加完以后,地图页的味道就变了。它不再只是一个"看一眼"的页面,而是变成了一个你真有可能反复打开的页面。
有时候不知道吃什么,翻翻它,反而挺有用。
不是所有记录都应该直接上地图
真实数据不会那么听话。总会有一些记录的位置不完整,或者根本不适合渲染到地图上。
所以我这里不是查出来就直接丢 marker,而是先做一轮标准化和过滤。只保留那些位置信息真的成立的记录。
这一步做完,页面的稳定感会好很多。
地图和卡片不联动的话,地图页就会很木
我很不喜欢那种地图归地图、列表归列表的页面。
所以这里做成了:
- 点地图上的点,下面卡片跟着切
- 滑下面卡片,地图中心和高亮 marker 跟着动
其实写法不复杂,但效果特别明显。用户不会说"你这个联动真优雅",他只会觉得"嗯,这页面挺顺手"。
而这就够了。
07. 登录这件事,最烦的从来不是"点一下登录"
很多小程序项目的登录都写得很快:有按钮,点了能进,就算完成。
但只要项目稍微像样一点,登录真正麻烦的地方就会冒出来:
- 登录态怎么存
- token 什么时候过期
- 过期以后怎么处理
- 每个页面是不是都要自己判断一遍
我这里是用 login_handler 云函数做登录,逻辑不花哨,就是:
- 通过微信上下文拿
OPENID - 查
users - 生成
authToken - 带上过期时间返回给前端
前端再统一做:
- 本地缓存登录信息
- 请求自动带 token
- token 失效自动清理
- 需要登录的页面统一拦截
做完之后最大的感受是,页面会清爽很多。
因为每个页面都不用再写一遍"如果没登录怎么办"的碎逻辑,很多事收口到公共工具里,后面迭代会轻松不少。
08. 收藏我单独做了一套,没有塞进记录表里凑合
这个地方我一开始也想过,是不是直接在记录上挂个 isFavorite 就完了。
后来想想,还是不对。
因为"收藏"不是"这条记录被标了一下",它更像是"我对这家店有持续兴趣"。
所以我单独做了 favorites 集合。
这么一拆,整个东西就活了很多:
- 收藏可以有自己的列表页
- 可以记录收藏来源
- 可以和地图、详情、记录产生更自然的关系
比如来源我就做了几种:
- 朋友推荐
- 小红书看到
- 偶然路过
这种信息很轻,但它会让一条收藏不只是"点了一下星",而是带着一点场景感。
09. 报告页我果断扔给云函数了
报告页这种东西,我的态度一直很明确:能在服务端聚合,就别让前端硬算。
因为它本质上不是展示页,而是统计页。
这里面要做的事包括:
- 累计消费
- 累计打卡
- 平均消费
- 最近 7 天 / 4 周趋势
- 分类占比
- 趣味数据
如果这些都让前端自己拉全量记录来算,短期能跑,后面一定越来越沉。
所以我这里直接让 getReportStats 云函数来聚合,前端只负责拿结果和渲染图表。
这样后面你想加一个统计维度,脑子也不会炸。
10. 成就系统不是刚需,但它真的很适合这类项目
说实话,成就系统不是这个项目"必须有"的功能。
但我就是觉得,这种偏生活记录的小程序,如果只有"记"和"看",会有一点平。
所以我加了一套勋章,比如:
- 首次打卡
- 深夜食堂
- 高分猎手
- 标签达人
- 连续打卡王
它不是为了把项目做得像游戏,而是想给"我又记了一条"这件事一点点反馈。
我一直挺在意这种轻微的情绪价值。功能当然重要,但很多项目做完以后之所以显得干,就是因为它只有功能,没有回声。
11. 这个项目里,我最满意的不是哪个页面,而是几个小处理
真要说我最满意的地方,其实不是地图页,也不是报告页,而是一些很小的处理。
第一,页面之间不是靠暴力刷新交流
新增、编辑、删除之后,不同页面会受影响,但我没有让它们每次都全量重来,而是做了轻量同步和 dirty 标记。
这很像收拾桌子:不是每掉一粒灰就把整间屋子掀一遍。
第二,登录成功的反馈会被带回目标页
这个细节我自己挺喜欢的。
如果你是从首页被引导去登录,那回来以后,首页会接住你,而不是让登录页自己喊一句"成功了"就结束。
页面之间有没有这种"交接感",真的差很多。
第三,我把重复而机械的事交给了脚本
项目里云函数不算少,所以我加了批量部署脚本,也加了鉴权片段同步脚本。
我越来越觉得,脚本最大的意义不是炫技,而是把那些"明明不难但特别烦"的重复劳动拿掉。
12. 如果继续往下做,我会优先补什么
这个项目现在已经能完整跑通流程了,但如果继续认真做,我下一步大概会优先补这几块:
- 数据库索引
- 分环境配置
- 云函数接口和字段文档
- 页面截图和演示数据
尤其是文档这件事,很多人都会拖。可一旦项目开始变复杂,你很快就会发现,代码不是唯一会过期的东西,脑子里的约定也会。
13. 最后想说的
我做完这个项目以后,一个感受特别深:
一个小程序最难的,往往不是某个 API 会不会调,也不是某个页面能不能画出来,而是你能不能把很多不起眼的小地方接顺。
比如:
- 登录过期后怎么处理
- 打卡完别的页面怎么跟上
- 地图页是不是只是个装饰
- 收藏是不是一个独立对象
- 报告页该在前端算还是后端算
这些问题单独看都不吓人,但项目到底像不像样,常常就看它们。
所以如果你也在做微信小程序,我会很建议你别满足于"能增删改查就行"。再多想一步:用户做完这一步,接下来会发生什么?
很多时候,项目质感就是从这一步里长出来的。
14.总结
这个项目做到这里,核心流程已经基本跑通了,包括登录鉴权、打卡记录、图片上传、位置选择、地图足迹、收藏体系和消费统计等几个主要模块。
回过头看,这个项目里真正花时间的,往往不是某个页面本身,而是页面之间怎么衔接、登录态怎么统一处理、数据更新后其他页面怎么跟上、统计逻辑应该放前端还是放云函数。
如果后面继续迭代,我会优先补这几块:
- 数据库索引优化
- 分环境配置
- 云函数接口和字段文档
- 页面截图与更细的模块拆解文章
如果你也在做微信小程序项目,希望这次复盘能给你一些实现上的参考。