用途
Currency Input 是一种专门用于输入货币金额的表单字段模式。它把数字字段的原始数值输入行为,与本地化格式、货币符号显示和金融校验约束结合在一起。
与通用数字输入不同,货币输入会在用户输入时格式化数值(例如显示 $1,299.99 而不是 1299.99),根据货币处理小数精度(美元使用 2 位小数,日元使用 0 位),并按地区惯例放置货币符号或代码。
适用场景
- 电商结账:购物车总额、折扣码、优惠券金额。
- 银行与金融表单:转账金额、存款金额、贷款申请。
- 费用报销:带货币上下文的报销金额。
- 订阅与定价配置:管理界面中的套餐定价。
- 预算与预测工具:财务规划输入。
不适用场景
- 展示价格(只读):应使用格式化文本,而非输入框。
- 无货币含义的数量:应使用数字输入。
- 超大或超小的科学数值:应使用带适当记法的标准数字输入。
- 货币无关的场合:普通数字输入更简单。
实现流程
- 在复制示例前,先确认该模式与问题和约束匹配。
- 从 references/pattern.md 中的结构和示例入手,然后选择最小可行的变体。
- 在叠加视觉打磨之前,先应用无障碍、性能和交互防护栏。
- 使用测试指南验证键盘、屏幕阅读器、响应式和失败场景下的行为。
无障碍防护栏
键盘交互模式:
| 按键 | 操作 |
|---|---|
| Tab | 将焦点移到货币输入框 |
| Shift + Tab | 将焦点移到上一个元素 |
| 0–9 | 输入数字 |
| . 或 , | 输入小数分隔符(取决于地区) |
| Backspace | 删除最后一个字符 |
| Delete | 删除光标后的字符 |
| 左/右方向键 | 在输入框内移动光标 |
性能防护栏
- 初始渲染:货币输入框出现 < 80ms
- 失焦格式化:数值格式化 < 16ms
- 货币选择器切换:更新符号和占位符 < 50ms
- 校验反馈:失焦后 < 150ms
- 内存占用:每个货币输入实例 < 5KB
常见错误
对货币使用 type="number"
问题:<input type="number"> 会显示浏览器微调箭头,拒绝千位分隔符(逗号),并且在不同浏览器和地区下对小数处理不一致。
错误示例:
<input type="number" step="0.01" min="0" />
修复方式:使用 type="text" 配合 inputmode="decimal"。
<input type="text" inputmode="decimal" pattern="[0-9]*[.,]?[0-9]{0,2}" />
在用户输入时格式化
问题:在 input 事件中重新格式化数值会导致光标意外移动,尤其是在输入过程中添加千位分隔符时。
修复方式:仅在失焦时格式化;输入过程中显示原始十进制输入。
input.addEventListener('blur', () => {
const raw = parseFloat(input.value.replace(/[^0-9.-]/g, ''));
if (!isNaN(raw)) {
input.value = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
}).format(raw);
}
});
input.addEventListener('focus', () => {
// Strip formatting for editing
input.value = input.value.replace(/[^0-9.]/g, '');
});
向服务器提交已格式化的值
问题:把 "$1,299.99" 发送给期望 1299.99(或整数分 129999)的后端,会导致解析错误或金额不正确。
修复方式:使用隐藏输入保存原始值,或在提交前去除格式。
<input type="text" id="amount-display" value="$1,299.99" />
<input type="hidden" id="amount-raw" name="amount" value="1299.99" />
form.addEventListener('submit', () => {
const raw = parseFloat(displayInput.value.replace(/[^0-9.]/g, ''));
hiddenInput.value = raw.toFixed(2);
});
相关模式
- https://uxpatterns.dev/patterns/forms/text-field
完整实现细节、示例和测试说明,请参见 references/pattern.md。
模式页面:https://uxpatterns.dev/patterns/forms/currency-input