微信小程序记账模板开发实战:从本地存储到数据统计实现
2026/9/14 22:48:59 网站建设 项目流程

简介:面向个人记账场景的微信小程序模板源码,适合微信小程序开发者和想要快速上线记账工具的团队或个人,提供从品牌引导页、账号登录、记账中心、消息通知到通讯录管理、个人中心的完整功能闭环,避免从零搭建的重复工作。压缩包共393个文件,大小约769KB,主要由WXML页面结构、WXSS样式、JS业务逻辑、JSON页面配置构成,并包含png、jpg、gif等大量界面素材,源码目录清晰,适合对照学习数据绑定、事件处理、状态管理和微信API调用等常见技术点。已有567人学习,能够为小程序入门者提供完整的代码范例,也为二次开发提供可靠基线。模板中的记账中心支持收支分类、金额、日期和备注输入,同时包含消息提醒与通讯录共享账单等扩展功能,开发者可根据实际需求直接调整分类、预算、主题和页面文案,快速打造个性化的日常记账应用。

1. 日常记账微信小程序模板源码的核心价值:直接改而不是从零写

先给结论:日常记账微信小程序模板源码不是拿过来改个名字就上线,它是用来“裁剪”的。记账类小程序看起来只有增删改查,实际上一旦动手,分类、账户、统计口径、日历分组、图表联动会连续占用几个周末。模板的意义在于把那些反复重写的页面骨架、数据字段、存储约定和统计函数先固定下来,让你把精力放到业务差异和交互体验上。微信小程序自身的 setData 性能特性、iOS 下日期解析、金额浮点误差这些基础性问题,模板已经替你先趟过一遍。适合三类人:第一次做微信小程序的新手、用课程设计或毕设选题来做项目实例的学生、以及原本用 HBuilderX 或 uniapp 开发、想回看原生实现的外包开发者。下面就从模板目录和数据层开始,把“已更新”这个前缀翻译成看得见的改动点。

2. 拆解日常记账微信小程序模板的页面与数据层

2.1 目录结构与页面清单

微信小程序模板的目录结构遵循原生约定:根目录是 app.js、app.json、app.wxss,页面放在 pages,公共组件放 components,工具函数放 utils。日常记账模板会多出三个页面:账本列表、分类管理、月度统计。目录主体大致长这样:

project-root/ ├── app.json ├── app.js ├── app.wxss ├── pages/ │ ├── index/index.wxml │ ├── index/index.js │ ├── index/index.wxss │ ├── record/record.wxml │ ├── record/record.js │ ├── record/record.wxss │ ├── stats/stats.wxml │ ├── stats/stats.js │ └── categories/categories.js ├── components/ │ ├── account-picker/ │ ├── category-picker/ │ └── month-switcher/ └── utils/ ├── format.js └── storage.js

这个目录结构说明模板的拆分策略:index 是账目流首页,record 负责新增和编辑单笔记录,stats 是月份切换和图表统计,categories 单独管理收入支出分类。components 里三个组件几乎不用改就能复用到其他项目,account-picker 做账户选择弹层,category-picker 根据收入还是支出过滤分类,month-switcher 处理带年份的月份切换。改需求时先判断字段是否通用——像账户选择这种能力,我一般保留组件,只在页面里传参数。

模板页面清单常配一张简化表,方便动工前确认哪些文件不用改:

文件路径职责改动频率
pages/index首页账目流与总余额
pages/record新增编辑单笔记账极高
pages/stats月度支出收入统计
pages/categories自定义分类列表
components/account-picker账户选择弹层

2.2 账目数据的字段设计与本地存储

日常记账最怕“先存起来,再发现字段不够”。模板里通常预置一组核心字段,统一定义在 storage.js 中。一个标准化账单对象大致长这样:

// utils/storage.js 中的账单字段定义 const BILL_FIELDS = { id: 'timestamp+random', // 唯一标识,避免使用自增数字 type: 'expense', // income / expense 二选一 category: '餐饮', // 与分类表联动 amount: 1250, // 以“分”为单位存整数,展示时再转元 account: '微信', // 账户或支付方式 date: '2025-04-01', // 记账日期,统一为 yyyy-mm-dd time: '08:30', // 具体时间,排序用 remark: '早餐', // 备注 createdAt: Date.now() // 创建时间戳 };

这段代码里最需要留意的是amount字段。如果直接用浮点数存 12.5,多次累加后,部分 iOS 机型上会出现 36.899999 之类的结果。模板把金额以“分”为单位存整数,就是为了把精度问题从账本里拿走。用户输入元时,用Math.round(parseFloat(value) * 100)转成整数,展示时再除以 100 并调用 toFixed(2)。

本地存储的读写使用的是微信同步方法。记账写入频繁、数据量小,同步方式编写更简单。读取时必须处理新用户无缓存的情况,模板一般给默认空数组:

// utils/storage.js function getBills() { const data = wx.getStorageSync('daily_bills'); return Array.isArray(data) ? data : []; } function saveBills(bills) { wx.setStorageSync('daily_bills', bills); }

参数说明:daily_bills是模板声明的存储键,修改键名时要全局搜索,不能只改保存不读取。Array.isArray判断是必要的,旧版本模板升级后可能残留其他格式的数据,直接返回会造成渲染层读取undefined

2.3 模板的统计与图表模块

统计是记账软件的核心模块。模板的统计页通常提供三项基础指标:本月支出、本月收入、结余,再配一个按日期的支出柱状图。原生微信小程序没有内置图表组件,模板会用 canvas 手绘,或引用轻量级图形插件。使用 canvas 方式时有一个避不开的坑:canvas 宽高必须在 WXML 里直接写死,开发工具里显示正常,真机上则可能糊掉,需要按设备像素比缩放。

统计逻辑通常写在 stats.js 中,核心思路是Array.prototype.filter配合reduce,计算过程与页面 setData 分离,这就是纯函数,放到小程序外部也能测试。模板中的月度统计通常写为:

// pages/stats/stats.js 中的统计函数 function getMonthStats(bills, yearMonth) { const prefix = yearMonth + '-'; // 形如 '2025-04-' return bills.filter(item => item.date.indexOf(prefix) === 0) .reduce((acc, item) => { if (item.type === 'expense') acc.expense += item.amount; else acc.income += item.amount; return acc; }, { expense: 0, income: 0 }); }

这里用字符串前缀匹配而不是new Date比较,目的是避开 iOS 对yyyy-MM-dd格式解析为无效日期的问题。调用时机放在onShow而不是onLoad,这样从 record 页面返回 index 或 stats 时,数据才会刷新。后续想改统计口径,只需要动 reduce 内部逻辑,页面结构不用动。

3. 用微信开发者工具把日常记账模板跑起来

3.1 导入模板与 AppID 配置

导入模板的完整流程:先安装微信开发者工具并用管理员账号登录,点击“导入”,选择模板源码所在目录,AppID 填自己注册的 ID;如果只想看界面,也可以使用“测试号”,但测试号不支持真机预览和云开发,正式接入建议直接注册个人主体小程序。这里最容易卡住的点是目录选错:有人选了外层压缩包解压目录,导致project.config.json嵌套在子目录里,工具提示“文件不存在”。检查标准是根目录下同时存在project.config.jsonapp.json

导入后记得打开“详情”面板,确认本地设置里的“将 JS 编译成 ES5”已开启,否则低版本机型会报语法错误。“已更新”的模板通常也适配了新版基础库,调试基础库版本不必选最高,能覆盖你真机的系统版本即可。

常见做法是先用测试号编译通过,再换成线上 AppID。此时 project.config.json 里这样配置:

{ "appid": "你的小程序AppID", "projectname": "daily-bookkeeping", "setting": { "es6": true, "postcss": true, "minified": true }, "srcMiniprogramRoot": "" }

参数说明:es6启用后,模板中的 async/await 和 let/const 会在低版本基础库上被转译;postcss负责处理 wxss 中的 rpx 兼容;srcMiniprogramRoot为空表示项目根目录就是小程序根目录。若模板存放在较深的路径,不要手动改这个字段,在开发者工具里移除项目后重新导入更可靠。

3.2 本地缓存与云开发的数据源切换

“已更新”模板常把数据层抽成两种实现:本地缓存版和云开发版。本地缓存版所有账目存手机,适合单机记账,但删除微信或换手机会丢数据;云开发版把账单集合存云端,可支持多设备同步。模板里二者通常用一行开关切换,位置在 app.js 顶部:

// app.js 中的数据源开关,二选一 const DATA_SOURCE = 'local'; // 'cloud' 表示云开发 const CLOUD_ENV = 'cloud1-xxxx'; // 云开发环境 ID if (DATA_SOURCE === 'cloud') { wx.cloud.init({ env: CLOUD_ENV, traceUser: true }); }

这段逻辑的含义是:业务页面不直接调用存储 API,而是访问utils/storage.js中封装的 getBills / saveBills,再由内部函数决定走缓存还是云数据库。切换云开发的步骤是:打开开发者工具工具栏中的“云开发”,创建环境,再把环境 ID 填到 CLOUD_ENV。模板里的集合一般叫bills,权限建议设为“仅创建者可读写”,避免账目泄露。

3.3 修改刚进入的加载页面与自定义导航栏

模板默认启动页是pages/index/index。要修改启动页,需要同步处理两处:app.jsonpages数组第一项,以及entryPagePath字段,新版基础库更认后者。模板若已支持自定义导航栏,会在 window 配置中加:

{ "window": { "navigationStyle": "custom", "navigationBarTextStyle": "black", "navigationBarBackgroundColor": "#ffffff" } }

自定义导航栏能把“日常记账”标题嵌入到页面内部,视觉上更像原生应用,但坑在顶部安全区计算。微信小程序顶部导航栏高度并不是固定值,iPhone 全面屏和 Android 差异很大。模板一般会在utils/system.js里用statusBarHeight + 胶囊按钮高度 + 胶囊到顶部距离计算。真机调试时,如果按钮挤到左上角,先检查是否读取了getMenuButtonBoundingClientRect(),这是自定义导航栏适配最常见的遗漏点。

4. 把模板逻辑改成自己的记账规则

4.1 分类增删改与颜色映射

模板预置的分类通常是餐饮、交通、购物、住房、娱乐、医疗、教育、人情。一旦业务需要让用户自己新增分类,就必须用可持久化的分类表,而不是硬编码数组。分类管理页面可以用这个写法:

// pages/categories/categories.js Page({ data: { categories: [], colors: ['#ff9900', '#5ac8fa', '#34c759', '#ff3b30'] }, onShow() { this.setData({ categories: this.getCategories() }); }, getCategories() { return wx.getStorageSync('bill_categories') || []; }, addCategory() { const list = this.getCategories().concat({ id: Date.now(), name: '未命名分类', color: this.data.colors[this.getCategories().length % 4] }); wx.setStorageSync('bill_categories', list); this.setData({ categories: list }); } });

代码里的addCategory先读取当前分类列表,追加一个新对象,再同时写缓存和页面数据。分类的 id 用Date.now()生成,避免出现重名分类无法区分的场景。颜色映射放在分类对象字段里,不要单独用数组下标对应颜色,否则删除某个分类后,后面的分类颜色会整体错位。

分类变更会影响历史账单。这里容易忽略的是分类改名后,老账单显示的名称也要跟着变。正确做法是不批量改账单数据,而在账单渲染层建立 name 到最新 category 的颜色映射,让列表按分类 id 去查当前分类信息。

4.2 金额精度处理与月度统计口径

金额输入控件有一个老问题:<input type="number">在部分真机上无法弹出带小数点的键盘,记账场景直接失效。模板标题里的“已更新”通常会把它改成type="digit",这是微信小程序才有的输入类型。如果排查模板发现仍是 number,直接替换:

<input class="amount-input" type="digit" placeholder="0.00" bindinput="onAmountInput" />

处理金额输入的第一步是限制小数位数,防止用户输入 12.333。可以在onAmountInput回调里用正则处理:

onAmountInput(e) { let v = e.detail.value; v = v.replace(/^(\d+)(\.\d{0,2})?.*$/, '$1$2'); if (!v) v = '0'; this.setData({ amountText: v }); }

参数说明:正则^(\d+)(\.\d{0,2})?.*$中,第一组确保整数部分,第二组最多保留两位小数,小数点后多余内容全部丢弃。这样输入框即便粘贴了长数字串,也能被自动截断。

月份统计口径隐藏着一个跨年 bug。getMonthStats用字符串前缀匹配,虽然避开了 iOS 日期解析问题,但会把跨年数据混进同个月前缀。更严格的写法应该是:

function getMonthStats(bills, yearMonth) { return bills.filter(item => { return item.date.length >= 7 && item.date.slice(0, 7) === yearMonth; }).reduce(/* 后续聚合逻辑 */); }

这里用slice(0, 7)截取年加月,再用严格相等判断,字符串前缀匹配的误伤问题就消失了。模板源码如果仍在用 indexOf,建议改成这种写法,避免 1 月统计到去年 12 月、或者2025-04匹配到2025-040这类脏数据。

4.3 账本数据导出与 wx.env.user_data_path

日常记账用久了,最实际的迁移需求是把缓存里的账目导出来。模板没有管理后台,导出功能可以做成设置页里的“导出账本”按钮,利用FileSystemManager.writeFile把 JSON 写入wx.env.USER_DATA_PATH

// utils/export.js const fs = wx.getFileSystemManager(); function exportBillsToFile() { const bills = wx.getStorageSync('daily_bills') || []; const filePath = `${wx.env.USER_DATA_PATH}/daily_bills_${Date.now()}.json`; fs.writeFile({ filePath, data: JSON.stringify(bills), encoding: 'utf8', success: () => { wx.showModal({ title: '导出完成', content: filePath, showCancel: false }); }, fail: (err) => { console.error('导出失败', err); } }); }

wx.env.USER_DATA_PATH是微信小程序当前唯一的可靠本地文件根目录,新基础库已经废弃了直接写 /tmp 的旧用法,所以模板更新后必须使用该路径拼接。用户拿到 JSON 文件后,可以自行用脚本转成 Excel。若模板已接入 uniapp,只需把wx.getStorageSync替换成uni.getStorageSync,文件接口保持同名,迁移成本并不高。

5. 模板上线前的数据校验与备份恢复

5.1 用实数据做一次统计口径回归

模板上线前,先用一组带边界条件的账本做测试:包含 12 月 31 日、1 月 1 日、金额为 0、金额为两位小数、跨月记录。把这份数据写进wx.setStorageSync('daily_bills', testData),再重进首页,检查列表条数与统计页显示是否一致。测试重点是看“本月支出”是否只包含当月,兼容 1 月 1 日时不能出现去年 12 月数据。

如果模板里用的是item.date.indexOf(prefix) === 0,请补上严格截取判断:

const ym = item.date.slice(0, 7); if (ym !== yearMonth) return false;

这段判断加上后,统计数据才不会被日期前缀破坏。开发工具里除了用“本地数据缓存”面板写入测试数据,也可以在设置页临时写一段 seed 函数,用完后删除,避免把测试代码带到线上版本。

5.2 备份键一致性检查与一键恢复

日常记账主账本通常存在daily_bills键,分类存在bill_categories键。备份时需要同时备份这些键,少一个都会导致恢复不完整。在开发者工具控制台执行:

const all = wx.getStorageInfoSync(); console.log(all.keys);

这段命令会列出当前小程序全部缓存键。如果你配置的是已更新模板,可能会看到旧版本的billsbill等历史键。恢复时不要只把名称替换掉,要先把旧键数据读取出来,按新字段规则做过一次标准化,再统一写入daily_bills。这样用户更新模板后,之前记的账才不会丢。

导入功能实现上可以用wx.chooseMessageFile选择导出的 JSON,解析后做字段过滤,再调用wx.setStorageSync写回。全部写完后,不要用wx.navigateBack返回旧页面,而是执行wx.reLaunch重新加载到首页,确保页面 onShow 里读到的是新数据。reLaunch 之前先wx.hideLoading,避免页面重复触发加载态,这是真机上最容易忽略的时序问题。

本文还有配套的精品资源,点击获取

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

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

立即咨询