推荐使用 Intl.NumberFormat 实现金额千分位格式化,它跨平台兼容性好、支持地区习惯且精度准确;若需手写正则,须处理负数和浮点误差,但优先复用 formatter 实例并预处理数据。

uni-app 里用 filter 做金额千分位格式化,不推荐
uni-app 的 filter 在 Vue 3(即 @vue/composition-api 或 setup 语法)中已被移除,H5 端可能兼容,但小程序端(微信、支付宝等)基本失效。你写好了 filters 对象,模板里写 {{ price | toThousands }},结果什么都没变——不是写错了,是根本没执行。
真正可靠的方式是:封装成函数 + 在 setup 或 data 中调用,或用计算属性。
- 别在
filters里写逻辑,尤其涉及正则或字符串处理时,跨平台行为不可控 - 微信小程序编译后会忽略
filters,支付宝、字节小程序同理 - 如果项目还在用 Vue 2 模式(
main.js里用了Vue.filter),仅限 H5 有效,其他端无效
用 Intl.NumberFormat 最省心也最准
浏览器和主流小程序基础库(微信基础库 2.19.0+、支付宝 10.2.80+)都已支持 Intl.NumberFormat,它自动处理千分位、小数位、货币符号、地区习惯(比如印度用 lakh 分隔),比手写正则靠谱得多。
直接在 setup 里定义一个格式化函数:
const formatMoney = (value) => {
if (value == null) return '0.00'
const num = Number(value)
return new Intl.NumberFormat('zh-CN', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
}).format(num)
}
-
'zh-CN'确保用中文分隔符(逗号),不是英文的点或空格 - 不要传字符串进去,先
Number()转一下,否则Intl可能返回Invalid - 小程序真机调试时,低版本基础库可能不支持
maximumFractionDigits,建议固定用minimumFractionDigits: 2+ 后续截断
手写正则格式化要注意数字精度陷阱
如果必须自己写(比如要兼容极老基础库),别用 .toFixed(2) 直接拼接,它对 0.1 + 0.2 这类浮点数会出错,显示 0.30000000000000004。
- 先用
Math.round(num * 100) / 100四舍五入到分,再转字符串 - 正则匹配整数部分:
str.replace(/(\d)(?=(\d{3})+\.)/g, '$1,')—— 注意这个正则只处理带小数点的情况 - 更稳妥的写法是:先
num.toFixed(2)→String(num).split('.')→ 分别处理整数/小数部分 → 再拼接 - 别忘了处理负数,
-12345.67格式化后应为-12,345.67,正则容易漏掉负号
在 v-for 列表里频繁格式化,性能有影响吗?
影响很小,但可优化。每次渲染都调用 Intl.NumberFormat 构造函数,会产生轻微开销;手写正则每次执行也有计算成本。
- 把
Intl.NumberFormat实例提成常量,复用:const formatter = new Intl.NumberFormat('zh-CN', {...}) - 避免在模板中直接调用函数,如
{{ formatMoney(item.price) }},改用计算属性或map预处理数据 - 列表项超过 100 条时,建议在请求后端数据后,统一格式化好再存入
ref或store,而不是渲染时实时算
最麻烦的其实是小数精度控制和负数符号位置——这两个点一旦出错,用户一眼就能看到钱不对,比样式错位严重得多。











