html中无原生精度校验属性,需用javascript监听input事件配合正则截断小数位;step仅控制步长且不阻止非法输入,无法替代精度校验,服务端必须基于原始字符串校验小数位数。

HTML 中没有原生的“精度校验”属性(比如 precision 或 step 用于小数位数控制),所谓“精度校验”实际是指对数值型输入的小数位数进行限制或验证,必须靠 JavaScript 配合 input 事件 + 正则/字符串处理实现,step 属性仅控制合法值步长,不拦截非法小数位输入。
为什么 step 不能替代精度校验
step 属性只在表单提交或调用 checkValidity() 时参与校验,且它校验的是“值是否为 step 的整数倍”,不是“小数位数是否合规”。例如 <input type="number" step="0.01"> 允许用户输入 1.234 —— 浏览器不会报错,因为 1.234 是合法数字,只是不满足 step 约束(1.234 ÷ 0.01 = 123.4 不是整数),但这个校验默认不触发视觉反馈,也不阻止输入。
常见错误现象:1.234 被允许输入并提交,后端收到超精度数据;用户以为输对了,其实业务要求“最多两位小数”。
-
step对type="text"完全无效 - 移动端软键盘可能忽略
step,直接弹出数字键盘但允许输入任意小数 - 即使
step="0.01",valueAsNumber仍可能返回1.2340000000000001(浮点误差),不能直接用于位数判断
用 input 事件实时截断或提示超精度输入
监听 input 事件,在用户每次按键、粘贴、删除后立即检查小数位数,并主动修正或标记状态。关键不是“阻止输入”,而是“不让非法精度残留”。
实操建议:
- 用正则提取数字部分:
const numMatch = value.match(/^[-+]?\d*\.?\d*$/),避免匹配到非数字字符 - 分离整数与小数:
const [_, intPart = '', decimalPart = ''] = value.match(/^(-?\d*)\.?(.*)$/) || [] - 若
decimalPart.length > 2,自动截断为前两位:value = `${intPart}.${decimalPart.slice(0, 2)}` - 调用
setCustomValidity('')清空旧错误,再根据结果设置新提示:input.setCustomValidity(decimalPart.length > 2 ? '最多支持2位小数' : '') - 注意中文输入法组合过程:
compositionstart/compositionend事件中暂停校验,避免误截“1.2”还没上屏就被干掉
服务端必须校验小数位数,前端不能信任
任何前端截断或提示都可被绕过:禁用 JS、手动修改 DOM、用 curl 提交 {"price":"999.12345"}。后端收到数据后,必须用语言原生方式解析并校验位数。
示例(Node.js):
const num = parseFloat(req.body.price);
if (isNaN(num)) throw new Error('非数字');
const decimalCount = (req.body.price.split('.')[1] || '').length;
if (decimalCount > 2) throw new Error('小数位数超过2位');
注意:不能只用 num.toFixed(2),那只是格式化,不是校验;必须基于原始字符串判断小数位,否则浮点数序列化会丢失精度(如 0.1 + 0.2 → "0.30000000000000004")。
最易被忽略的一点:精度校验的语义属于业务规则,不是通用数值约束——100.00 和 100 在数值上相等,但某些系统要求显式保留两位小数,此时必须校验原始字符串格式,而非转换后的数字。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











