site logo

Marico's space

如何使用 JavaScript 构建小费计算器

前端技术 2026-09-25 11:28:03 5

最近折腾了一个小费计算器,本来以为半小时能搞定,结果在除法取整和输入验证上踩了几个坑。这篇把实现过程和踩过的坑都说清楚,给想练手的同学当个参考。

小费计算器的核心逻辑很简单:输入账单金额和小费比例,算出小费金额和总额,再支持按人数分摊。拿餐厅场景举例,120元的账单,18%的小费比例,就是21.6元小费,总共141.6元。

小费计算器需要什么

用 JavaScript 做小费计算器,需要三个核心输入:账单金额、小费比例、分摊人数。前两个算出小费,第三个用来算每个人出多少钱。

核心公式就四条:

  • 小费金额:账单 × 小费比例 ÷ 100
  • 总金额:账单 + 小费金额
  • 人均总金额:总金额 ÷ 人数
  • 人均小费:小费金额 ÷ 人数
输入项 示例 用途
账单金额 ¥120.00 小费前的消费金额
小费比例 18% 用于计算小费的百分比
人数 3 分摊账单的人数

按照上面这个例子,小费是21.6元,总共141.6元。三个人平摊的话,每人47.2元。

先搭 HTML 界面

界面上放三个输入框:账单金额、小费比例、人数。然后留几个位置显示计算结果。

1. 创建输入框

先写一个简单的表单:

<label for="bill">Bill amount</label>
<input id="bill" type="number" min="0" step="0.01" placeholder="60.00"> <label for="tip">Tip percentage</label>
<input id="tip" type="number" min="0" step="0.1" placeholder="18"> <label for="people">Number of people</label>
<input id="people" type="number" min="1" step="1" value="1"> <button id="calculate">Calculate Tip</button> <p>Tip: <span id="tipAmount">$0.00</span></p>
<p>Total: <span id="total">$0.00</span></p>
<p>Per person: <span id="perPerson">$0.00</span></p>

用 number 类型的输入框,浏览器会自动调出数字键盘。配合 min 和 step 属性,能限制输入范围,防止用户瞎填。

2. 给结果显示位留好 ID

结果显示的地方各自带上唯一 ID,这样 JS 才能精准找到并更新内容。计算逻辑和显示逻辑分开,后续改起来也方便。

加上 JavaScript 计算逻辑

JS 的活就是:读取三个输入框的值,转成数字,按公式算完,再把结果写回页面。

1. 读取输入值

const billInput = document.getElementById("bill");
const tipInput = document.getElementById("tip");
const peopleInput = document.getElementById("people"); const tipAmount = document.getElementById("tipAmount");
const total = document.getElementById("total");
const perPerson = document.getElementById("perPerson"); document.getElementById("calculate").addEventListener("click", calculateTip);

输入框拿到的是文本,需要转成数字才能做运算。Number() 转换一目了然:

const bill = Number(billInput.value);
const tipPercent = Number(tipInput.value);
const people = Number(peopleInput.value);

2. 计算小费

小费比例换算成小数,再乘以账单金额。

const tip = bill * (tipPercent / 100);

120元的账单,18%小费,JS 算出来就是 120 × 0.18,等于 21.6。

3. 计算总额

const totalAmount = bill + tip;

总额就是原始账单加上小费。

4. 分摊金额

用总金额除以人数,得到每个人要付的钱。

const amountPerPerson = totalAmount / people;

当然也可以单独算人均小费:

const tipPerPerson = tip / people;

5. 显示结果

用 textContent 把值塞进对应的元素:

tipAmount.textContent = `$${tip.toFixed(2)}`;
total.textContent = `$${totalAmount.toFixed(2)}`;
perPerson.textContent = `$${amountPerPerson.toFixed(2)}`;

toFixed(2) 保留两位小数,符合大多数货币显示习惯。

处理验证和货币取整

一个能用的计算器,必须能处理空值、非法数字、人数为零这些情况,否则一除就崩。

输入验证

function calculateTip() { const bill = Number(billInput.value); const tipPercent = Number(tipInput.value); const people = Number(peopleInput.value); if (!Number.isFinite(bill) || bill < 0) { return; } if (!Number.isFinite(tipPercent) || tipPercent < 0) { return; } if (!Number.isInteger(people) || people < 1) { return; } const tip = bill * (tipPercent / 100); const totalAmount = bill + tip; const amountPerPerson = totalAmount / people; tipAmount.textContent = `$${tip.toFixed(2)}`; total.textContent = `$${totalAmount.toFixed(2)}`; perPerson.textContent = `$${amountPerPerson.toFixed(2)}`;
}

这版代码会拒绝负数账单、负数比例、非数字、以及人数为零或小数的情况。实际项目中最好在对应输入框旁边显示错误提示,让用户知道哪里出了问题。

取整规则

货币计算一般需要两位小数。JavaScript 的 Math.round() 可以四舍五入取整。

const roundedTotal = Math.round(totalAmount);

不过显示用 toFixed(2) 更合适:

const displayTotal = totalAmount.toFixed(2);

记住计算用的数值和显示用的格式化要分开存。内部保留精确结果,界面只做展示用的格式化。

关于分摊时的分分钱

分摊账单经常会出现分分钱除不尽的情况。比如100.01元除以3人,结果是个无限循环小数。三个人的显示金额四舍五入后加起来,可能跟总额差一分钱。

简单场景下,显示每人四舍五入后的金额就够了。但如果要做支付系统精确对账,就得定个明确的余数处理规则,比如把最后一分钱塞给某个人。

让计算器更好用

基础功能跑通了,可以再加几个体验优化。

加几个快捷比例按钮

常见的15%、18%、20%做成按钮,一键填入,不用每次都打字:

<button type="button" data-tip="10">10%</button>
<button type="button" data-tip="15">15%</button>
<button type="button" data-tip="18">18%</button>
<button type="button" data-tip="20">20%</button>

JS 把选中的值塞进输入框:

document.querySelectorAll("[data-tip]").forEach(button => { button.addEventListener("click", () => { tipInput.value = button.dataset.tip; calculateTip(); });
});

这样比例值写在 HTML 里,JS 只负责交互逻辑,职责分明。

输入时实时计算

改成用户边输入边出结果,不用每次都点按钮:

[billInput, tipInput, peopleInput].forEach(input => { input.addEventListener("input", calculateTip);
});

改金额、调比例、加人减人,结果马上更新,体验顺滑很多。

测一下边界情况

发布前多测几个例子,不要只测一个正常的120元账单。边界情况最容易暴露问题:

  • 空账单
  • 零账单
  • 负数账单
  • 小数账单
  • 零小费
  • 小数比例
  • 一个人
  • 很多人
  • 非法人数
  • 除不尽的分摊

好的测试用例应该有独立算出来的预期结果,这样对答案检查 JS 输出才对得上。

保证可访问性

每个输入框都要有可见的标签,用 for 和 id 关联起来。结果标签也要写清楚,比如“小费金额”、“总额”、“人均”,用户扫一眼就知道每个数是什么意思。

常见问题

JavaScript 怎么计算小费?
账单乘以小费比例再除以100。比如120元的20%小费,就是24元小费。

怎么算总金额?
小费加回原始账单。120元加24元小费,总共144元。

怎么分摊小费?
用小费金额或总金额除以人数。注意处理除不尽时的小数取整问题。

JavaScript 怎么取整?
Math.round() 四舍五入到整数,toFixed(2) 格式化成两位小数用于显示。

小费计算器需要后端吗?不需要。所有计算都在浏览器里完成,页面参数输入完直接出结果。

怎么验证非法输入?
计算前先校验账单、比例、人数。拒绝负数,人数为零或非法时不做除法。

能支持不同货币吗?能。计算逻辑跟货币无关,换个符号或格式就行,百分比公式照旧。

小费计算器是个不错的 JavaScript 练手项目,核心算法就那么几行,但界面要考虑验证、格式化、分摊、用户体验这些实际问题。基础版跑通之后,可以加币种选择、税费计算、常用预设、更复杂的分账逻辑,扩展空间不小。