跳转到内容

V1: 从零开始 —— 「老板说做个记账工具」

你刚入职一家20人的创业公司,老板说公司报销全靠Excel,经常对不上账,让你做个简单的记账系统,先自己用着试试。

当前状态: 什么都没有,从零开始。 目标: 做一个个人记账工具,能增删改查费用记录,有个仪表盘看月度总额和分类汇总。 约束: 只有你一个人用,不需要服务器,打开 HTML 文件就能用。


层级问题思考
Why为什么要做这个?Excel无法追踪变更历史,数据不结构化无法做统计
What做什么?费用CRUD + 月度统计仪表盘
How (架构)怎么组织?纯前端,localStorage存数据,不需要后端
How (实现)具体怎么写?单HTML文件 + JS + CSS,数据存浏览器本地
How (部署)怎么跑起来?直接双击打开HTML文件,零安装零配置

为什么不直接用后端? 现在只有你一个人用,不需要共享数据。localStorage完全够用。等团队其他人也要用了,再考虑加后端——那是V2的事。


graph LR
subgraph 浏览器
HTML["HTML + JS + CSS"] --> LS["localStorage<br/>(数据)"]
end
style 浏览器 fill:#e8f4f8,stroke:#333

没有服务器,没有数据库,数据就在浏览器里。 双击 HTML 文件就能用。

// 数据直接存在浏览器的 localStorage
const expenses = JSON.parse(localStorage.getItem('expenses') || '[]')
// 每条记录的结构
{
id: Date.now(), // 用时间戳做唯一ID,够用了
amount: 1050, // 单位:分,避免浮点精度问题(10.50元 = 1050分)
category: '餐饮', // 餐饮/交通/办公/团建/其他
date: '2024-01-15', // 字符串格式
note: '团队午餐'
}
功能实现方式
新增费用表单提交 → 存入 localStorage
查看列表读取 localStorage → 渲染表格
按月筛选JS 过滤数组
编辑费用表单回填 → 更新 localStorage
删除费用过滤数组 → 重新存入
月度汇总JS 计算 → 展示总额和分类统计
决策点选项A选项B选择理由
金额存储float(元)int(分)int(分)避免浮点精度问题,0.1+0.2≠0.3
存储方案localStorageindexedDBlocalStorage数据量小,JSON够用
框架React/Vue原生JS原生JS单文件工具,不需要构建环境
样式自己写CSSCDN引入TailwindCDN Tailwind零安装,直接用

帮我做一个单文件的个人记账工具,就一个 HTML 文件,打开就能用,不需要服务器。
## 需求
1. 费用CRUD:新增、列表、编辑、删除
2. 按月筛选,默认显示本月
3. 仪表盘:当月总支出、按分类(餐饮/交通/办公/团建/其他)的汇总金额
4. 数据用 localStorage 存储,刷新不丢失
## 数据结构(存到 localStorage 的 JSON)
每条记录:
- id: 时间戳
- amount: 整数,单位是分(10元 = 1000分)
- category: 字符串,枚举:餐饮/交通/办公/团建/其他
- date: 字符串,格式 2024-01-15
- note: 字符串,备注
## 技术要求
- 单个 HTML 文件,不需要构建工具
- 用 CDN 引入 Tailwind CSS(直接加 script 标签)
- 金额显示用元(/100),存储用分(*100),避免浮点问题
- 金额输入框允许小数点两位(如 10.50 元)
## UI 要求
- 顶部:月份选择器 + 总支出显示
- 分类汇总:各分类金额列表
- 费用列表:日期、分类、金额、备注、编辑/删除按钮
- 新增/编辑:一个表单,填完点保存
请直接输出完整的 HTML 文件。

  • 双击 HTML 文件能在浏览器打开,不报错
  • 新增一条费用,刷新页面后数据还在
  • 金额显示正确(输入 10.50,显示 ¥10.50)
  • 按月筛选后只显示当月记录
  • 月度总额计算正确(手动验算)
  • 编辑费用后数据正确更新
  • 删除费用后从列表消失
  • 分类汇总金额与列表明细之和一致

知识点对应模块
localStorage:浏览器本地存储的工作原理→ Module 2(数据存储)
JSON序列化/反序列化:数据如何在内存和字符串之间转换→ Module 2(数据存储)
整数存储金额:为什么0.1+0.2≠0.3→ Module 2(数据模型)
前端CRUD:DOM操作和事件处理的基础模式→ Module 1(API设计)

// 错误:用浮点数存金额
{ amount: 10.50 } // 10.5 * 3 = 31.500000000000004
// 正确:用整数存分
{ amount: 1050 } // 1050 * 3 = 3150(分)
// 输入时转换(元 → 分)
const cents = Math.round(parseFloat(input.value) * 100)
// 显示时转换(分 → 元)
const yuan = (cents / 100).toFixed(2) // "10.50"
localStorage 上限约 5MB,存文本数据
一条记录大概 200 字节
5MB / 200B = 约 25000 条记录
个人记账每天最多几十条,几年也不会满
如果数据多了,V2 再考虑后端存储
// 错误:忘了从 localStorage 读取,每次页面加载都用空数组
let expenses = []
// 正确:页面加载时从 localStorage 初始化
let expenses = JSON.parse(localStorage.getItem('expenses') || '[]')
localStorage 数据只在同一浏览器的同一域下共享
如果你在两个标签页同时打开同一 HTML 文件(file:// 协议),
改一个标签页,另一个不会自动更新
暂时无解——这就是 V1 的限制。
等 V2 加了后端,所有人都从服务器读数据,就解决了。

V1 的局限,以及为什么 V2 需要后端

Section titled “V1 的局限,以及为什么 V2 需要后端”

V1 用 localStorage 有一个根本限制:数据只在你自己的电脑上

  • 换台电脑就没数据了
  • 同事无法看到你的记录
  • 老板要查账,你得把 HTML 文件发给他

当老板说「给团队10个人也用上」,你就会发现 localStorage 不够用了——那时候才真正需要引入后端。

这就是 V2 要解决的问题。