You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 12:27:46