应使用math.floor(math.abs(num) 100) / 100截断再tofixed(2),并做null、空字符串和nan兜底,避免四舍五入及异常;示例:vue.filter('money', function(value) { if (value == null || value === '') return '0.00'; const num = number(value); if (isnan(num)) return '0.00'; const truncated = math.floor(math.abs(num) 100) / 100; return truncated.tofixed(2); });

直接用 toFixed(2) 会出问题,比如 123.0 变成 "123.00" 没毛病,但 0.005 会四舍五入成 "0.01",而业务上常要求「截断」而非「四舍五入」;更麻烦的是,toFixed 对负数、NaN、空字符串等边界值处理不鲁棒,直接调用容易在渲染时抛错或显示 "NaN.00"。
全局过滤器里怎么安全地保留两位小数
推荐在 main.js 中定义 money 过滤器,但别裸用 toFixed:
- 先做类型兜底:用
Number(value)转数字,再用isNaN()判是否有效,无效时返回"0.00" - 避免四舍五入干扰:用
Math.floor(num * 100) / 100实现向下截断(如1.239 → 1.23),再补零 - 补零逻辑必须手动做:
.toFixed(2)虽然能补零,但前提是数字本身合法;更稳妥写法是(Math.floor(num * 100) / 100).toFixed(2) - 示例代码片段:
Vue.filter('money', function (value) {<br> if (value == null || value === '') return '0.00'<br> const num = Number(value)<br> if (isNaN(num)) return '0.00'<br> const truncated = Math.floor(Math.abs(num) * 100) / 100<br> const fixed = truncated.toFixed(2)<br> return num })
输入框 blur 时格式化成 x.xx,但不能影响用户正在输入
别在 @input 里实时格式化——会导致光标跳动、输入中断。正确时机是 @blur 或 @confirm(软键盘回车):
- 拿到原始
value后,先trim()去首尾空格,再replace(/[^0-9.-]/g, '')清洗非法字符 - 允许多个点?不行。用
replace(/\.+/, '.')确保最多一个点,再用replace(/^\.|(\.)\./g, '$1')去掉开头点和重复点 - 转数字后判断范围:若超出
min/max,直接赋值为边界值,再走截断+补零流程 - 特别注意:用户输
"12."是合法中间态,blur时应自动补成"12.00",而不是报错或清空
为什么不能只靠 CSS 或 display 属性控制小数位
CSS 的 text-align: right 或 font-family: monospace 不影响数值精度;input 的 step="0.01" 在部分安卓机型上无效,且无法阻止用户粘贴非法字符串(如 "12.3456");v-model.number 会把 "12.34" 自动转成 12.34,但失去字符串精度控制权,后续再 toFixed(2) 就可能因浮点误差变成 "12.340000000000002"。
真正要稳,就得在数据落地前完成清洗和截断——不是展示层的事,是数据层的契约。











