Flutter:基于货币代码实现价格输入与格式化显示
解决方案:脱离Locale的货币格式化TextField实现
核心思路是完全自定义货币格式规则,不依赖系统Locale,通过维护一份ISO 4217标准的货币格式元数据,实现输入和显示的精准控制。
1. 构建货币格式元数据映射表
先定义所有需要支持的货币的关键格式参数:货币符号、千分位分隔符、小数分隔符、小数位数。这份数据可从ISO 4217官方标准提取,确保准确性。
// 示例核心映射,需补充完整的货币代码 const currencyFormatRules = { "USD": { symbol: "$", thousandSep: ",", decimalSep: ".", decimalDigits: 2 }, "EUR": { symbol: "€", thousandSep: ".", decimalSep: ",", decimalDigits: 2 }, "GBP": { symbol: "£", thousandSep: ",", decimalSep: ".", decimalDigits: 2 }, "JPY": { symbol: "¥", thousandSep: ",", decimalSep: ".", decimalDigits: 0 }, "INR": { symbol: "₹", thousandSep: ",", decimalSep: ".", decimalDigits: 2 }, "BHD": { symbol: "ب.د", thousandSep: ",", decimalSep: ".", decimalDigits: 3 } };
2. 实现通用格式化函数
写一个纯函数,接收数字和货币代码,返回符合规则的格式化字符串。针对特殊货币(如INR的3-2分组)单独处理。
function formatCurrency(amount, currencyCode) { const rules = currencyFormatRules[currencyCode]; if (!rules) return amount.toString(); // 未知货币降级为原始数字 // 处理小数位数 const fixedAmount = Number(amount).toFixed(rules.decimalDigits); const [integerPart, decimalPart] = fixedAmount.split('.'); // 格式化整数部分(处理特殊分组) let formattedInteger; if (currencyCode === 'INR') { // 印度卢比分组规则:从右往左每2位分隔,最后一组3位 formattedInteger = integerPart.replace(/(\d)(?=(\d{2})+(?!\d))/g, '$1,').replace(/^,/, ''); } else { // 通用千分位分组 formattedInteger = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, rules.thousandSep); } // 拼接结果 let result = rules.symbol + formattedInteger; if (rules.decimalDigits > 0) { result += rules.decimalSep + decimalPart; } return result; }
3. TextField输入处理逻辑
监听输入事件,先清理用户输入的无效字符,再转换为数字后调用格式化函数更新显示。以React为例:
import { useState } from 'react'; function CurrencyTextField({ currencyCode }) { const [rawInput, setRawInput] = useState(''); const [displayValue, setDisplayValue] = useState(''); const handleInputChange = (e) => { // 过滤输入:只保留数字和单个小数点 const cleanedInput = e.target.value.replace(/[^0-9.]/g, ''); const splitParts = cleanedInput.split('.'); const finalRaw = splitParts.length > 2 ? `${splitParts[0]}.${splitParts.slice(1).join('')}` : cleanedInput; setRawInput(finalRaw); // 格式化显示 if (!finalRaw) { setDisplayValue(''); return; } const amount = Number(finalRaw) || 0; setDisplayValue(formatCurrency(amount, currencyCode)); }; return ( <input type="text" value={displayValue} onChange={handleInputChange} placeholder={`输入金额 (${currencyCode})`} aria-label={`${currencyCode} 金额输入框`} /> ); }
4. 关键注意事项
- 货币数据完整性:需要补充完整的ISO 4217货币代码映射,可从官方标准导出后整理成JSON文件,按需加载。
- 负数处理:如果业务需要支持负数,在格式化函数中添加负号判断,将符号放在货币符号前(如-$1,234.56)。
- 性能优化:货币规则数据较大时,可拆分常用货币和小众货币,实现懒加载。
- 符号正确性:部分货币有多个符号变体(如CAD的$和C$),需根据业务场景选择标准符号。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

