利用状态机判断输入的下一位字符是否能被接受,来决定是否阻止按键事件。此方法的优点是能动态地确定下一个按键是否有效,相较于正则的新思路。
<html>
<head></head>
<body>
<input id="money"/>
<script>
let inputElem = document.getElementById("money");
function isMoney(text,e){
let shouldPrevent = false;
let dotOnce = false;
let fractionCount = 0;
function start(code){
if(typeof code === "undefined") return end;
if(!/[\d]/.test(code)){//第一个只能接受数字
shouldPrevent = true;
return end;
}else{
return number;
}
}
function number(code){
if(typeof code === "undefined") return end;
if(code === "."){
return dot(code);
}else{
if(fractionCount >=2){//小数不能多于2位
shouldPrevent = true;
return end;
}
if(dotOnce){fractionCount++;}
return number;
}
}
function dot(code){
if(typeof code === "undefined") return end;
if(dotOnce){//小数点只有一个
shouldPrevent = true;
return end;
}
dotOnce = true;
return number;
}
function end(){
if(shouldPrevent){
e.preventDefault();
}
}
let mochine = start;
let index = 0;
do{
mochine = mochine(text[index]);
index++;
} while(mochine!==end)
mochine();//执行终结函数退出
}
function makeMap(str, expectsLowerCase) {
const map = Object.create(null);
const list = str.split(',');
for (let i = 0; i < list.length; i++) {
map[list[i]] = true;
}
return expectsLowerCase ? val => !!map[val.toLowerCase()] : val => !!map[val];
}
const whiteList = "Backspace,ArrowLeft,ArrowRight";//不会被阻止的按键
const inWhiteList = makeMap(whiteList);
inputElem.addEventListener("keydown",function(e){
const value = e.target.value;
const key = e.key;
const nextStr = value + key;
if(!inWhiteList(key)){//不在白名单里的按键
if(!/[\d\.]+/.test(nextStr)){//数字和小数点为有效字符
e.preventDefault();
}else{
isMoney(nextStr,e);
}
}
});
</script>
</body>
</html>