前几天,在公司项目中遇到一个给金额添加千分位的需求,于是一直想着有空来整理一下,一直没抽出时间,今天有空,整理一下。
2023.09.11更新:前端有自带的方法,我是看到这篇博客的时候才知道的:
js处理金额显示格式(最简单)_js 金额格式_@前端小菜的博客-CSDN博客
整理如下:
function moneyFormats(value) {
return Number(value).toLocaleString('zh', { style: 'currency', currency: 'CNY', minimumFractionDigits: 2 });
}
moneyFormats('555555.445')
// '¥555,555.45'
moneyFormats('88888888888888888888888888888')
'¥88,888,888,888,888,900,000,000,000,000.00'
/*
* Number.toLocaleString() 第二个参数:
* style: 格式化时使用的样式(默认"decimal")
* 👉 "decimal"表示纯数字格式, "currency"表示货币格式, "percent"表示百分比格式
* currency: 在货币格式化中使用的货币符号(没有默认值,如果样式是"currency",必须提供货币属性)
* 👉 "USD" 表示美元, "EUR" 表示欧元, "CNY" 表示人民币
* minimumFractionDigits: 使用的小数位数的最小数目
* 👉 可能的值是从0到20,默认为普通的数字和百分比格式为0
*/这个方法有个小问题,Number(value)转为数字格式的时候,会有有效位数的问题。
不过换个角度想想,好像也没这么大金额的,如果确认金额不带小数的话,可以这样(当然带小数转BigInt就会报错了):
function moneyFormats(value) {
return BigInt(value).toLocaleString('zh', { style: 'currency', currency: 'CNY', minimumFractionDigits: 2 });
}
// moneyFormats('555555.445')
// 报错 Uncaught SyntaxError: Cannot convert 555555.445 to a BigInt
moneyFormats('88888888888888888888888888888')
// '¥88,888,888,888,888,888,888,888,888,888.00'那么,可以灵活处理一下,反正小数部分也是照搬下来(四舍五入一下),所以只用处理整数
(上班中午休息的时候手写的,简单测试了下没发现问题,如果有问题再说)
const fractionalCount = 3 // 保留x位小数
function moneyFormats(num) {
if (isNaN(num)) {
return '-'
}
// 将 数字/字符串类型的数字 转换为 字符串,并按小数点拆分为整数部分和小数部分
let parts = (num + "").split(".")
if (parts.length > 2) {
return "-" // 不是数字
}
// 整数部分
let integerPart = BigInt(parts[0]).toLocaleString('zh', { style: 'currency', currency: 'CNY', minimumFractionDigits: 0 })
// 小数部分(考虑精度问题就稍微麻烦一点,核心思路就是按要保留小数位数截断,然后多取1位判断是否需要进位)
let fractionalPart = ""
if (fractionalCount > 0) {
if (parts.length > 1) {
let fLen = parts[1].length
if (fLen > fractionalCount) { // 需要四舍五入
if (parts[1][fractionalCount] >= 5) { // 需要进位
let fractionalBigInt = BigInt(parts[1].substring(0, fractionalCount))
fractionalPart = (fractionalBigInt + 1n).toString()
} else { // 不需要进位
fractionalPart = parts[1].substring(0, fractionalCount)
}
} else { // 需要在后面补 0
let zeroCount = fractionalCount - fLen
fractionalPart = parts[1] + new Array(zeroCount).fill('0').join('')
}
} else {
// 小数部分全是 0
fractionalPart = parts[1] + new Array(fractionalCount).fill('0').join('')
}
fractionalPart = '.' + fractionalPart
}
// console.log('fractionalPart', fractionalPart)
return integerPart + fractionalPart
}
moneyFormats('888888888888888888888888888888888888888888.444444444444444444445')
// '¥888,888,888,888,888,888,888,888,888,888,888,888,888,888.444'
moneyFormats('00000111111.4')
// '¥111,111.400'
moneyFormats('00000111111.95')
// '¥111,111.950'在网上简单搜了一下,主要有几种方式,比较常规的代码判断这里就不再重复了,主要是想整理一下正则的处理方案。
项目中用到了echarts,感觉应该echarts中应该会有相关的功能。大胆猜想,如果echarts也使用了正则处理这个逻辑,那\d肯定会出现在正则中,同时每三位添加一个逗号,那正则中很有可能出现\d{3}之类的部分。果不其然,一搜,发现真有。

这两个就是从echarts中摘出来的代码:
o.addCommas=function(t){return isNaN(t)?"-":(t=(t+"").split("."),t[0].replace(/(\d{1,3})(?=(?:\d{3})+(?!\d))/g,"$1,")+(t.length>1?"."+t[1]:""))}
function tu(t){return isNaN(t)?"-":(t=(t+"").split("."))[0].replace(/(\d{1,3})(?=(?:\d{3})+(?!\d))/g,"$1,")+(1<t.length?"."+t[1]:"")}

分析了一下,其实这两个代码功能是一样的,只是可能用的打包工具有些差异,所以最终压缩后的代码不完全一样。
我把上面这个函数美化了一下,加了点注释,代码逻辑是等价的
function addCommas(num) {
if (isNaN(num)) {
return '-'
}
// 将 数字/字符串类型的数字 转换为 字符串,并按小数点拆分为整数部分和小数部分
let parts = (num + "").split(".")
// 整数部分 从右往左匹配
let integerPart = parts[0].replace(/(\d{1,3})(?=(?:\d{3})+(?!\d))/g, "$1,")
// 小数部分
let fractionalPart = parts.length > 1 ? "." + parts[1] : ""
return integerPart + fractionalPart
}这样就一目了然了,如果想炫技的话,可以写到一行:
function addCommas(num) {
return isNaN(num) ? "-" : (num = (num + "").split("."))[0].replace(/(\d{1,3})(?=(?:\d{3})+(?!\d))/g, "$1,") + (num.length > 1 ? "." + num[1] : "")
}上面这种更适合严谨一点的需求,因为他同时带一些校验,比如非数字字符串等等。
如果能够确保入参是数字,数字字符串或者是null,undefined,那么可以简单一些,像这样:
function addCommas(val) {
if (typeof val === 'undefined' || val === null) {
return ''
}
return (val + "").replace(/(\d)(?=(\d{3})+\.)/g, '$1,');
}
// console.log(addCommas('')) // ''
// console.log(addCommas('0')) // '0'
// console.log(addCommas(null)) // ''
// console.log(addCommas(undefined)) // ''再进一步,如果是前端展示金额的话,可以像这样:(注意toFixed会四舍五入,这里要按照实际业务来决定是四舍五入还是向下取整)
2023.09.11备注:前端 toFixed() 并不是四舍五入,也不是向下舍入,所以涉及到金额显示,请谨慎使用!
参考这篇博客:https://www.only4.work/blog/?id=519
function priceFormat(val) {
val = Number(val)
if (val) {
return "¥" + val.toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,');
} else {
return '¥0.00'
}
}到这里整理的就差不多了,希望能够帮到大家。
本文由张小弟之家原创,转载请注明出处。
本站文章除注明转载/出处外,均为原创,若要转载请务必注明出处。转载后请将转载链接通过邮件告知我站,谢谢合作。本站邮箱:admin@only4.work
尊重他人劳动成果,共创和谐网络环境。点击版权声明查看本站相关条款。
GitHub登录