上一周公司的一个项目中发现了一个问题:有一个输入框是要输入手机号码的,但是这个输入框当时没有做限制,可以输入任意字符,所以被报了 BUG。
需求:这个输入框只能输入 11 位手机号
我一看,这不是很简单的事情吗,但是实现的时候,发现事情并没有那么简单。
解决方法
常见的解决方法
<input
type="text"
onkeyup="this.value=this.value.replace(/[^0-9]/gi, '').slice(0,11)"
/>
一行解决,但效果不太好,如图。
试一下 onkeypress
<input
type="text"
oninput="this.value = this.value.replace(/[^0-9]/gi, '').slice(0,11);"
/>
这代码有问题,还能输入其他字符?
改了一下代码
<input type="text" onkeypress="validate(event)" />
function validate(evt) {
var theEvent = evt || window.event;
// Handle paste
if (theEvent.type === "paste") {
key = event.clipboardData.getData("text/plain");
} else {
// Handle key press
var key = theEvent.keyCode || theEvent.which;
key = String.fromCharCode(key);
}
var regex = /[0-9]|\./;
if (!regex.test(key)) {
theEvent.returnValue = false;
if (theEvent.preventDefault) theEvent.preventDefault();
}
}
这次效果是不是好很多了?然而,如果用户右键复制粘贴,强行输入了字符串怎么办?
继续改,换个监听方式,oninput
<input
type="text"
oninput="this.value = this.value.replace(/[^0-9.]/gi, '').replace(/\./g, '').slice(0,11);"
/>
这次效果是不是好很多了?
还有网上找来的一些成熟的方法
function setInputFilter(textbox, inputFilter) {
[
"input",
"keydown",
"keyup",
"mousedown",
"mouseup",
"select",
"contextmenu",
"drop",
].forEach(function (event) {
textbox.addEventListener(event, function () {
if (inputFilter(this.value)) {
this.oldValue = this.value;
this.oldSelectionStart = this.selectionStart;
this.oldSelectionEnd = this.selectionEnd;
} else if (this.hasOwnProperty("oldValue")) {
this.value = this.oldValue;
this.setSelectionRange(this.oldSelectionStart, this.oldSelectionEnd);
} else {
this.value = "";
}
});
});
}
setInputFilter(document.getElementById("myTextBox"), function (value) {
return /^\d*\.?\d*$/.test(value);
});
然而,事情还没那么简单
我浏览器 F12 看了一下代码,发现,代码是 jsp 生成的,jsp 调用了某个 js 文件,这个 js 文件有点像生成模板字符串那样,生成了这个输入框。然后这个 js 文件我也不敢乱改,因为它是个公共组件,我改了的话,其他地方不知道又要出什么 BUG。F12 看到的 DOM 类似下面这种。
<input type="text" name="txt" value="Hello" onchange="myFunction(xxxx, this)" />
其中 myFunction
函数我还是可以改的。
我就改成下面这种了
function (data, el) {
// 对于手机字段,限制只能输入数字,个数不超过 11 位
if (type == "phone") {
var val = $(el).val();
val = val.replace(/[^0-9]/gi, "").slice(0,11);
$(el).val(val);
$(el).off("oninput");
$(el).on("oninput", function (event) {
val = val.replace(/[^0-9]/gi, '').slice(0,11);
});
}
}
onchange
会触发 myFunction
,这时候加上 oninput 的事件监听就可以了。
由于每次 onchange
都会触发一遍 myFunction
,所以要去掉 oninput
的事件监听,不然的话输入一次会加一次监听,输入 11 次,就会挂上 11 次的事件监听,就会执行 11 次事件。
虽然用户无感知,但是养成好习惯是有必要的。
其他笔记
事件监听的添加和移除
// Attach an event handler to <div>
document.getElementById("myDIV").addEventListener("mousemove", myFunction);
// Remove the event handler from <div>
document.getElementById("myDIV").removeEventListener("mousemove", myFunction);
onchange 没有 preventDefault()
onchange
事件的 event
是没有的 preventDefault()
的,见 cancelable
相关资料
参考文章
总结
一个小小的输入框校验,让我收获了很多。