☰
微信小程序记账本开发实战:架构、数据模型与真机避坑指南
2026/10/16 5:20:39 网站建设 项目流程

记账软件我前前后后换过好几款,也用过表格模板记过一阵子,最后都没坚持下来。后来干脆自己动手做了个小程序版本的记账本,用到现在两年多,每天记一笔大概花不了十秒,反而成了习惯。这篇文章就把我从零开发微信小程序记账本的完整过程拆开讲,包括为什么选小程序而不是 App、数据表怎么设计、金额精度怎么处理、统计图表怎么画,以及真机上踩过的一堆坑。如果你正打算给自己或团队做一个轻量记账工具,或者想用一个小而完整的项目练手小程序开发,这篇文章应该能帮你少走不少弯路。

1. 记账需求与小程序形态的匹配:记账难从来不是“记”的问题

1.1 记账场景的真实痛点

大多数记账产品的用户流失发生在同一个节点:坚持了两周,觉得麻烦,就放弃了。麻烦在哪里?打开 App、找入口、输入金额、选分类、填备注,一套流程下来二十秒起步。如果软件还时不时弹广告、劝你开会员,那弃用几乎是必然的。

真正能让人长期记账的产品,核心不是报表多华丽,而是把“记录一笔”这个动作压到最短。我给自己定的目标是:从掏出手机到记完一笔账,不超过十秒。围绕这个目标,产品设计上做了几个决定:

  • 默认选中上一次使用的分类,减少重复点击。
  • 金额键盘是自定义的,数字键大、响应快,不调起系统键盘。
  • 默认时间是当前时间,只有需要补记时才去改日期。
  • 首页直接放一个“记一笔”悬浮按钮,不藏在二级菜单里。

这些细节看着简单,实际开发中每一条都对应一套交互逻辑。比如“默认选中上次分类”,意味着本地要缓存用户的最近一次分类;比如自定义键盘,意味着输入框要处理光标、小数点、保留两位这些边界情况。记账类小程序看着轻,开发起来并不轻,坑全藏在交互细节里。

1.2 为什么是小程序而不是 App

其实一开始我也想过是不是做一个独立的 App,毕竟市面上记账 App 很成熟,做新的很难出头。但认真对比之后,我发现微信小程序的形态更适合这类轻工具场景。

第一,触达路径短。微信里搜一下、或者聊天中点开小程序卡片就能进,不需要去应用商店下载安装包。记账是一个高频但碎片化的行为,用户不是在“有需求”时主动去搜索,而是在消费当下顺手记录,小程序用完即走、下次再来的特征天然吻合。

第二,多端同步成本低。微信小程序天然跑在微信里,同一账号在不同手机上登录,数据只要放在云端,就不存在“换手机数据没了”的问题。如果自己做 App,要么自建后端,要么接第三方云,账密体系、数据同步、Token 过期这些全要处理,工作量完全不是一个量级。

第三,不用上架应用商店。小程序有自己的审核流程,但相对应用商店要轻量很多,迭代也方便,用户打开的就是最新版,不存在 App 更新率低导致的版本碎片问题。

当然,小程序也有它烦人的地方,比如审核、平台规则、插件兼容性这些,后面我会专门讲。

1.3 功能边界:第一版只做四件事

我第一次做这个项目时犯过一个典型错误:想一口气把所有功能都做进去,账户体系、多人共享账本、周期性账单、预算管理、报销统计…结果光设计数据表就搞了一个星期,代码却没写几行。后来把范围砍到只保留四个核心模块,整个项目两周就跑通了第一版:

模块作用优先级
记账支出、收入快速录入,支持备注、时间修改第一版必做
明细按月份展开流水,支持编辑删除第一版必做
统计按月汇总、分类占比、月度趋势第二版加
预算设置月度总预算,超支提醒第二版加

如果你也是第一次做这类项目,我建议第一版就做“记账 + 明细”,统计和预算甚至可以等用户真的产生记账习惯之后再迭代加。功能做少一点,用户上手门槛低,自己也更容易把每个页面打磨到可用状态。

2. 技术选型与整体架构:原生加云端,最朴素的组合

2.1 原生小程序还是跨端框架

市面上现在有不少跨端框架,比如基于类 Vue 或类 React 语法写一套代码,编译到小程序、H5、App 多端。要不要引入跨端框架,我的建议很简单:如果你和我一样,短期内只打算做微信小程序,用原生就是最快的路径。

原生开发的优劣势都比较明显。劣势是语法和写网页差得比较多,像是自定义组件、生命周期、页面通信这些都要单独学一遍;优势是调试工具成熟、平台新特性更新最快、依赖最少,遇到问题网上能搜到的解决方案也最全。

跨端框架适合的场景是“明确要覆盖多端”的项目。如果你今天想做小程序,明天想上 H5 和 App,那确实值得一开始就引入框架。但如果只是快速验证一个想法,原生加微信官方开发者工具足够了,没必要为了“以后可能做多端”提前背上框架的包袱。

另外,原生小程序直接用微信官方的基础组件库就够。UI 层面可以选一套第三方开源组件库,它们对样式、布局、弹层交互这些做了封装,比自己写样式表快很多。不过要注意版本兼容,有些组件库在基础库低版本上会出渲染问题,建议开发者工具里直接选最新的基础库做调试基准。

2.2 微信云开发:一个人也能搞定前后端

记账类应用表单简单,但数据是增量累积的,必须持久化。我选的是微信云开发,理由非常实际:

  • 不用自己买服务器、配域名、搞备案;
  • 自带登录能力,通过接口拿到用户 openid,天然区分不同用户;
  • 前端直接调用数据库 API,不需要自己写后端接口;
  • 控制台自带数据管理界面,直接查数据、改数据,开发期排查问题很方便。

云开发的架构大概是这样的:前端小程序通过云调用请求云函数或直接读写云数据库;云函数运行在服务端,可以做数据聚合、校验、定时任务;云数据库是文档型数据库,一个集合可以理解成一张表,每条记录是一个 JSON 文档。

整个项目我最终的目录结构如下:

project/ ├── cloudfunctions/ # 云函数目录 │ └── getMonthStat/ # 月度汇总聚合 ├── miniprogram/ │ ├── pages/ │ │ ├── index/ # 首页:本月概览、记一笔入口 │ │ ├── add/ # 记账页 │ │ ├── list/ # 明细页 │ │ └── stats/ # 统计页 │ ├── components/ # 自定义组件 │ ├── utils/ # 工具函数、常量 │ └── app.js └── project.config.json

开发期我用一个很顺手的技巧:在云数据库控制台把集合权限设为“仅创建者可读写”,这样数据天然按用户隔离,不用在每次查询条件里手动拼 openid。要注意的是,云函数端有管理员权限,不受这个权限限制,所以涉及聚合、统计的操作放到云函数里做,前端直接传条件,云函数内部按用户的 openid 再过滤一层。

2.3 全局配置与基础样式

小程序的页面配置和全局配置分别在app.json和各个页面的page.json里。tabBar 是底部导航栏,我的第一版只放了三个入口:明细、记账、统计。大多数记账 App 是把“记账”做成中间的大按钮,但第一版为了省事,我直接把记账入口也放成了 tab,后来证明这个决策还不错,单看转化路径,从打开小程序到进入记账页只需要一次点击。

样式方面,记账页是个对视觉要求比较高的地方。金额键盘、分类网格、日期选择器如果布局没对齐,真机上会特别显眼。我直接用 flex 布局加固定宽高实现九宫格和键盘,没有引入第三方 UI 库的键盘组件,因为这种强交互组件后期经常需要定制,自己写反而更好控制。颜色上选了一组清新的浅绿色作为主色,所有页面的操作按钮统一用这个主色,整体视觉会协调很多。

3. 数据模型设计:账本应用的地基

3.1 账目记录集合的字段设计

记账应用最核心的集合就是账单记录,我把集合名定为bills。字段设计上经历了几轮迭代,最终沉淀成下面这套:

字段类型说明
userIdstring用户 openid,用于数据隔离
typestring支出 / 收入
amountnumber金额,单位是“分”
categoryIdstring分类 ID,关联分类集合
categoryNamestring分类名称,冗余存储,便于历史展示
accountIdstring账户 ID,默认“现金”
datestring记账日期,格式 2024-01-15
timestring记账时间,格式 12:30
remarkstring备注,可空
createdAtnumber创建时间戳,服务端赋值

几个字段的取舍需要展开讲一下。categoryName我做了冗余存储,这是因为分类是可以被用户编辑的,如果用户把“餐饮”分类改名成“吃喝”,历史账单里的分类 ID 不会变,但如果在页面展示时临时去关联查询分类集合,会增加一次请求。直接把名称冗余进账单记录里,历史账单的展示就不会跟着分类的修改而变化。

date和time我在底层存的是字符串,而不是时间戳。原因是记账页需要按“日”维度过滤数据,比如查某个月的所有账单,字符串形式的日期配上数据库的范围查询条件,直接就能匹配,比时间戳换算成当地时区再比较要省事得多,尤其是后面要讲到的 iOS 时区问题。

3.2 金额精度的坑:为什么必须用“分”存储

这是记账类应用最容易踩的坑,我放置了好久才改过来。JavaScript 浮点数的精度问题大家都听过,0.1 + 0.2不等于0.3,这在记账场景里是致命的。比如一笔奶茶 18.5 元,再来一笔早餐 6.5 元,如果直接用元做浮点加法,结果可能变成 25.000000000000004,用户看到会觉得这产品有 bug。

我的处理办法很粗暴也很可靠:所有金额在存储和计算时都以“分”为单位,用一个整数表示,只在展示时除以 100 转成元。前端输入 18.50,内部马上转成1850,所有加减、聚合、比较都基于整数,最后渲染时再格式化。

// 输入元转分:注意字符串处理,避免浮点 function yuanToCents(yuan) { const arr = yuan.split('.'); const intPart = parseInt(arr[0] || '0', 10); const decimalPart = arr.length > 1 ? arr[1].padEnd(2, '0').slice(0, 2) : '00'; return intPart * 100 + parseInt(decimalPart, 10); } // 分转元:用于展示 function centsToYuan(cents) { return (cents / 100).toFixed(2); }

这里有个小陷阱,yuanToCents不能直接用parseFloat(yuan) * 100,因为浮点数乘法的结果也可能是不精确的,比如19.9 * 100在某些环境下会得到1989.999...。字符串解析是安全的。跟你日常记账用的是同一个道理,涉及金钱的运算,永远别碰浮点。

3.3 分类、账户、预算的独立集合

账单记录是事实表,分类、账户、预算这些属于“元数据”,单独建集合有利于后期扩展。

分类集合categories的字段比较简单:name、icon、type(支出或收入)、sortOrder、isDefault。预设分类我会在用户首次进入时通过云函数初始化,写入一批默认分类,比如餐饮、交通、购物、居住、娱乐等,每个分类配一个 SVG 图标的路径。如果之后用户想自定义分类,直接往集合里插记录就行。

账户集合accounts在最简版本里是可有可无的,但我还是保留了一个默认账户“现金”。如果你想记录“微信钱包”“银行卡”这类多账户的余额变动,账户表就需要更完整的字段,比如余额、图标、初始值。第一版不建议做太细,先保证账单记录能写进去。

预算集合budgets我设计的维度是“按月设置”,字段是month(比如 2024-01)、totalLimit(当月总预算,单位同样是分)。第一版只做整体预算,不做分类预算,等用户量多了再迭代分类预算。

// 云函数:初始化默认数据 exports.main = async (event) => { const openid = event.userInfo.openId; const db = cloud.database(); const defaultCategories = [ { name: '餐饮', icon: 'food', type: 'expense', sortOrder: 1 }, { name: '交通', icon: 'transport', type: 'expense', sortOrder: 2 }, { name: '购物', icon: 'shopping', type: 'expense', sortOrder: 3 } ]; await db.collection('categories').add({ data: defaultCategories.map(c => ({ ...c, userId: openid })) }); return { code: 0 }; };

一个必须提醒的点是:预算模块和账单记录之间的联动逻辑比想象中复杂。用户超出预算时,首页要展示提醒;Edit 历史账单时,预算的使用量也要同步变化。这块建议放到第二版再做,先把数据模型留好,后面接上不难。

4. 核心页面实现与交互细节

4.1 首页:月度汇总与“记一笔”入口

首页的作用是让用户一打开就“心里有数”:这个月花了多少、还剩多少。页面结构从上到下是本月支出汇总卡片、最近几笔流水、底部中央的“记一笔”按钮。

本月汇总卡片的数字,我用的是一个云函数来做按月聚合。云函数内部先算出用户 openid,然后以当月第一天和最后一天作为date字段的范围条件,查询当月所有支出记录,再对所有账单的amount求和。为什么不在前端做求和?因为前端读取的是分页数据,不完整,直接求和会漏掉后面的记录。

// 云函数 getMonthStat const start = `${year}-${month}-01`; const end = `${year}-${month}-31`; const res = await db.collection('bills') .where({ userId: openid, type: 'expense', date: db.command.gte(start).and(db.command.lte(end)) }) .field({ amount: true }) .get(); const total = res.data.reduce((sum, bill) => sum + bill.amount, 0);

这里有个性能细节:云函数单次返回的记录数有限,如果一个月内账单量超过几百条,需要分批聚合而不是一次性取回。我的做法是:用count()先查当月账单数量,如果超过 100 条,就按每天一个分组再聚合,避免云函数一次性拉回太多数据。家庭记账场景一个月最多几百条,这个方案完全够用。

最近几笔流水我直接在前端用数据库查询拉取,orderBy('date', 'desc').limit(10),额外加一个按月份过滤条件,展示最近一个月的。这里用onShow而不是onLoad拉数据,很关键:每次从记账页返回首页时都会触发onShow,这样用户记完账回到首页,数字和列表会立刻刷新。

4.2 记账页:金额键盘是灵魂

记账页是整个应用交互最重的页面。布局上,顶部是金额输入区,中间是分类网格,底部是我自己实现的自定义数字键盘。

关于金额输入,最麻烦的是光标和有效数字的处理。我的方案是:用一个>function onKeyPress(key) { let amount = this.data.amount; if (key === 'delete') { amount = amount.slice(0, -1); } else if (key === '.') { if (amount.includes('.') || amount === '') return; amount += '.'; } else if (key === 'confirm') { this.saveBill(); return; } else { const parts = amount.split('.'); if (parts.length === 1 && parts[0].length >= 6) return; if (parts.length === 2 && parts[1].length >= 2) return; amount += key; } this.setData({ amount }); }

分类网格每行四个,纵向滚动,默认选中上一次使用的分类。这个“记住上一次分类”的实现方式很简单:本地用wx.setStorageSync存一个lastCategoryId,每次进入记账页时读取并高亮。

保存逻辑里最容易漏的是数据校验。金额为空或为 0 时提示;分类没选时默认为餐饮;日期默认今天,可以点按后弹日期选择器改到昨天或更早。保存操作调用云数据库的add,成功后wx.navigateBack返回首页。这里我不建议用wx.showToast做成功提示,弹窗会打断节奏,直接返回上一页让用户看到数字变了,体验更顺。

4.3 明细页:按月份分页的流水列表

明细页按月份展示账单列表,每条记录展示分类图标、名称、备注、日期和金额。月份通过顶部的左右切换箭头,或者点击月份文字弹出一个日历选择器。

列表的数据加载我拆成了两层:先查当前月份的总条数(count()),再分段加载账单记录。小程序列表渲染大量节点会卡,尤其是某个月有几百条账单时,一次性setData几千个数组元素,真机上滚动会掉帧。我用了一个简单的分页加载:每次limit(20),滚动到底部时自动拉下一页,把新数据concat到旧数组后面。

编辑和删除功能我放在列表项的右键弹出菜单里,点击后进入一个简单的编辑页,表单字段和记账页一致,区别是保存时调用update而不是add。删除操作我做了二次确认弹窗,防止手滑把历史记录删掉。

这里有一个体验上的小细节:明细页按“日”做了分组汇总,展示“2月15日 支出 45.60元”,这其实是按月内日期聚合的查询。我最初没做分组,列表就是一长串流水,扫一眼根本看不出某天花了多少。加了日汇总后,信息密度高了很多,用户翻历史账单的体验提升明显。

4.4 统计页:图表与分类占比

统计页是数据价值的集中体现,我把它拆成三个区域:月度趋势折线图、分类支出饼图、每日支出柱状图。图表不是原生的能力,我引入了一个成熟的图表组件库,小程序图表库有一些开源方案,你可以按自己的熟悉程度选择。无论选哪个,实现逻辑基本一致:前端或云函数把数据按维度聚合好,图组件负责渲染。

月度趋势我是按月汇总支出的,这里一开始踩了个小坑:统计页要展示的是“过去六个月每月支出的走势”,我在云函数里用日期范围查了六次数据库,每次一个sum,结果云函数运行时间偏长。优化方式是:把最近六个月的所有账单一次性查出来,在前端按月份字段做分组求和,只查一次数据,云函数执行时间大幅下降。

分类占比饼图的实现思路类似。先用云函数查当月所有支出,再按categoryId分组聚合出分类金额。为了画饼图,还需要给每个分类配置一个百分比和颜色。这里我预设了 8 个固定颜色,按金额降序依次分配,如果分类数超过 8 个就循环复用。

统计页有个很容易被忽略的点:日期筛选的时间维度。饼图和柱状图应该是看“本月”的,但用户往往会切换到上个月、上上个月去对比。我的做法是顶部放一个月份切换器,切换时重新发起聚合请求。聚合请求属于读操作,云开发有缓存机制,但为了省云函数调用量,我加了前端wx.setStorageSync做本地缓存,用户快速切换月份时直接读缓存,延迟感几乎为零。

5. 开发中的要命坑:这些才是真正的绊脚石

5.1 日期解析:iOS 上的灾难现场

这是整个项目里折腾我最久的一个问题。在模拟器和安卓真机上一切正常的日期逻辑,一到 iOS 真机就出问题,典型的场景是:用户选择了2024-02-15这个日期,控制台打印出来却是Invalid Date。

问题的根源在于 iOS 的 JavaScript 引擎对日期字符串的解析规则和安卓不一致。iOS 下new Date('2024-02-15')会被解析成NaN,必须写成new Date('2024/02/15')或者拆成年月日再传参。听起来很简单,但代码里只要有一处遗漏,统计页、月份切换、日历选择器就全线崩溃。

保险的做法是:把日期字符串封装成一个工具函数,统一处理格式。同时我建议底层存日期格式时直接用YYYY-MM-DD这种纯字符串,不依赖Date对象来互相转换。这样既避开解析差异,也方便云数据库的范围查询,一致性最好。

5.2 云函数冷启动与前端体验

云函数有一个现象叫冷启动:第一次调用时函数实例需要初始化环境,耗时往往比后续调用长很多,可能达到 2 到 3 秒。记账页保存一笔账单时如果走了云函数,用户按下“保存”按钮要等两三秒才会有反馈,这个体验是灾难性的。

因为云开发的数据库权限里,前端是有权限直接往自己的账号下写入数据的,所以记账保存完全没有必要走云函数。我最终的处理方案是:前端调用数据库 API 直接读写账单数据,只有统计聚合才走云函数。这个调整让记账保存延迟从 1.5 秒级别降到了本地操作级别,体验接近原生 App。云函数负责读聚合数据时,冷启动的影响相对能接受,而且云的并发缓存机制会让后续调用快很多。

如果你把数据写入也放在云函数里,建议把写操作和读操作拆成两个函数,读函数的冷启动影响可以用前端缓存覆盖,写函数如果冷启动太久会给用户“卡住”的错觉。能用前端直连数据库解决的,尽量别往云函数里塞。

5.3 分页查询与聚合查询的记录数上限

云开发数据库单次查询默认返回 20 条,聚合结果返回 100 条,超过这个数量会直接被截断。这在账单量比较多的月份里会带来两类问题:

一是明细页分页没写对,翻了几页后发现后面的数据不加载了。解决方式是显式传入limit,并且理解云数据库的分页机制:skip加limit组合,但skip太大会有性能问题。对小体量项目来说,每页 20 条、最多翻 50 页的量级完全没问题;如果真的会超过千条,建议改用“按日期游标”的方式,用db.command.gt(游标)来取下一页,性能更好。

二是统计聚合时,如果当月账单超过 100 条,前端拉回的res.data是不全的。这时就要在云函数里做真正的分批拉取,或者用数据库的aggregate聚合方法直接按categoryId分组统计,后者是更优雅的方案。

// 云函数:按分类聚合当月支出 const $ = db.command.aggregate; const res = await db.collection('bills').aggregate() .match({ userId: openid, type: 'expense', date: db.command.gte(start).and(db.command.lte(end)) }) .group({ _id: '$categoryId', total: $.sum('$amount') }) .limit(50) .end();

聚合查询返回结果同样有上限,但如果分组数量没超过上限,这个方案是最省事的。我在代码里做了兜底,如果res.data不足预期数量,再去跑一个分批拉取的兜底逻辑。

5.4 分类删除后,历史账单怎么办

用户删除了一个自定义分类,比如“宠物”,那么过往所有标记为“宠物”分类的账单,在明细页和统计页就会显示成空白或未知分类。这个问题做第一版时我差点忽略。

我的处理方案是:删除分类时,把该分类 ID 对应的历史账单做一次批量更新,把它们统一归到一个默认分类“其他”下。这样历史数据不会丢失分类归属,统计时也能正常聚合。

// 云函数:删除分类并处理历史账单 await db.collection('bills') .where({ userId: openid, categoryId: event.categoryId }) .update({ data: { categoryId: 'default-other', categoryName: '其他' } }); await db.collection('categories').doc(event.categoryId).remove();

这里不建议直接把账单也删掉,哪怕用户删分类的初衷是“不想要这个分类了”,历史账单里的金额和消费记录仍然有保留价值。分类是展示维度,账单是事实记录,删维度不等于删事实,这两者的边界想清楚,产品逻辑就不会乱。

6. 测试、真机联动与后续迭代方向

6.1 真机调试的重要性

小程序开发里有一句形容得很贴切的话:模拟器是天堂,真机是战场。模拟器里样式、交互、性能全部正常,一上真机就会暴露各种问题。我踩过的真机专属坑至少有这几类:

  • 自定义键盘在 iPhone 底部的安全区内被手势条挡住,需要在页面底部加上safe-area-inset-bottom适配代码。
  • 安卓机的 WebView 里position: fixed的悬浮按钮偶发跳动,原因是输入框聚焦时视图大小变化,需要在弹出键盘时临时隐藏或重定位。
  • 图片懒加载在某些机型上不生效,懒加载模式只在特定基础库版本可用,真机预览时需要验证。
  • 开发者工具里的上传接口调用没有做域名校验,真机上如果改了云函数配置,很容易出现cloud.callFunction:fail的问题。

所以项目上线前,我会拿着一台 iOS 和一台安卓做全流程回归:新建账单、编辑账单、删除账单、月份切换、统计查询。宁可多花半天真机验证,也尽量不要只靠模拟器自信上线。

6.2 代码提交前要过的自查清单

开发完第一版后,我整理了一份自查清单,每次迭代都会过一遍:

  • 金额是否全部以“分”存储,展示格式化有没有遗漏;输入负数、0、小数超两位的情况是否都被拦截。
  • 日期字符串格式在任何地方都是YYYY-MM-DD,有没有直接拿字符串传给Date构造函数的地方。
  • 云函数的访问权限是否都加上了 openid 过滤,前端直连数据库的集合权限是否设置正确。
  • 删除分类、编辑账单、修改预算这些联动场景是否都正确处理了历史数据。
  • 页面刷新逻辑:onShow里有没有遗漏,用户从记账页返回后首页数字有没有更新。
  • 真机验证过的机型是否覆盖了两端,安全区适配是否到位。

这份清单看起来很基础,但每一条背后都是实实在在踩过的坑。记账应用用户每天用,任何一个小 bug 都可能被用户反复碰到,这类产品对稳定性要求比一般展示型工具要高得多。

6.3 后续可以做的扩展方向

第一版稳定上线后,积累了一批真实用户,就可以开始规划第二版。从我自己后来的迭代经验看,有几个扩展方向性价比最高:

  • 语音记账:用户在录音里说“早餐 12 块”,小程序后台识别后自动填好金额和分类。语音转文字能力接入起来不算难,关键是准确率。实测下来,在安静环境里简单句子的识别准确率能达到 90% 以上,很适合通勤路上随手记。
  • 周期性账单:房租、话费、订阅会员这类每月固定支出,设置一次后自动生成账单。这个功能对“坚持记账”帮助巨大,因为用户会发现每月不用手动记房租了,记账负担显著下降。
  • 数据导出:用户想把历史账单导出成 CSV 文件做二次分析。云函数生成文件后返回临时下载链接,前端走文件下载流程。
  • 多人共享账本:情侣或家庭共同记账。这涉及到账单归属从单用户变成多用户,数据表和查询逻辑都要改,建议在用户量达到一定规模、确实有需求反馈时再做。

我的建议是不要一次塞太多功能。记账应用的核心价值是“快速记录 + 清晰统计”,先把这两件事做到让人愿意天天打开,再考虑用扩展功能提升留存。技术架构上因为第一版已经留好了数据模型的扩展位,后面加功能不伤筋动骨,最重要的是别在最开始就过度设计。

回到开头说的那个目标:让记录一笔账不超过十秒。整个项目做下来,我最深的体会是,好用的工具不是功能多,而是每个交互都丝滑、每个数字都可信。如果你也想做一个小而美的记账小程序,从这篇文章的架构出发,先做减法再迭代,你会比自己预想中更快跑通第一版。后续真机测试时遇到 iOS 日期问题或者分页截断的坑,希望你能想起来这篇文章,少走我已经走过的弯路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询