应用场景:开发前端交互页面时,经常遇到金额输入框、指定小数位数的数字输入框,单一的正则表达式无法满足大部分的业务校验需求,下面总结一个实用巧妙而又灵活的把普通输入框变成自动校正输入框的解决方案:
数字(金额)输入框:
输入金额:<input id="money">
原生JS自动校正:
let dom = document.getElementById("money");
dom.addEventListener("input", function () {console.log(this.value);let inputValue = this.value;this.value = autoFixedDicimal(this.value, 3, true); // 示例:最多允许3位小数,可以为负数console.log(`\t\t输入:【${inputValue}】=>【${this.value}】=>转化为Number类型:【${Number(this.value)}】`);
});
/*** 自动校正数字输入框* @param inputValue 输入值* @param bitsAfterDot 小数点后最多允许的位数,默认2位* @param allowNegative 是否允许输入负数,默认否*/
function autoFixedDicimal(inputValue, bitsAfterDot, allowNegative) {// 处理参数的默认值if (bitsAfterDot == null || bitsAfterDot == undefined)bitsAfterDot = 2;allowNegative = allowNegative || false;// 自动校正输入的数字decimallet value = inputValue;// 先处理符号问题(负数)let mark = "";if (/^-/.test(value)) {mark = "-";}// 如果输入非数字,则替换为''value = value.replace(/[^\d\.]/g, '');// 必须保证开头为数字而不是小数点.value = value.replace(/^\./g, '');// 保证小数点.最多出现一次value = value.replace('.', '$#$').replace(/\./g, '').replace('$#$', '.');// 只能输入两位小数let reg = new RegExp(`^(\\-)*(\\d+)\\.([\\d]{0,${bitsAfterDot}}).*$`);value = value.replace(reg, '$1$2.$3');value = allowNegative ? mark + value : value;return value;
}
测试结果:
注意事项:
1.输入框的"input"事件主流浏览器都支持,IE的兼容性未测,如果不支持,可增加绑定"propertychange"事件。强大之处在于:输入框的值改变(键盘、鼠标、粘贴)都能检测到;
2.对于校正后的结果,最好使用Number(value)转化成Number类型,避免用户输入了小数点但小数点后面没有小数部分(截图);
3.如果你不想使用自动校正的功能,这里提供一个比较友好的校验可能包含有小数的正则表达式:/(^[1-9][0-9]*$|^0$)|((^[1-9][0-9]*|^0)[\.](\d)*$)/ 在光标移开事件blur或者提交前校验输入的数字是否合法。
最后小记一下:
之前在实际项目中自己也是花了很多时间写过类似的自动校验方法,比较复杂,文末会给出TypeScript版。上面的自动校验参考的是这篇博客自动校验,吸取别人的优点,也扩展了其功能。
以前自己写的TypeScript版:
/*** 金额自动校正* @param value 字符串类型* @param maxLengthAfterDot 小数点后最多允许多少位* @return 过滤后的字符串*/public static filterMoney(value, maxLengthAfterDot): string {// 先遍历去掉非数字非小数点.的字符let filtered = "";for (let c of value) {if ("0123456789.".includes(c)) {filtered += c;}}// 如果有多个小数点.,则去掉后面多余的小数点.let locationOfDot = filtered.indexOf(".");if (locationOfDot > -1) {filtered = filtered.replace(/\./g, "");filtered = filtered.slice(0, locationOfDot) + "." + filtered.slice(locationOfDot)}// 再用正则去校验let re = /(^[1-9][0-9]*$|^0$)|((^[1-9][0-9]*|^0)[\.](\d)*$)/if (!re.test(filtered)) {// console.error("输入金额不合法:", value);filtered = filtered.slice(0, -1);}// 小数点后最多maxLengthAfterDot位let re2 = /[\d]+\.(\d*)$/g;let execArray = re2.exec(filtered);if (execArray && execArray.length > 0 && execArray[1].length > maxLengthAfterDot) {// console.error(`小数点后面长度超过了${maxLength}位`);filtered = filtered.slice(0, -1);}return filtered;}