从一次输入框无法输入的bug,谈如何限制输入框输入类型
bug的产生和修改
上周临近周末休息的时候,一个同事跑过来了,对我说:“阿伦啊,有一个页面出问题了,火狐浏览器所有的input都没法输入了。”我一听,是不是你给加了什么属性,让input输入框只读了啊。看了一下代码,很正常的一个输入框,并且CSS写的也很正常。
<input id="ipt-message" type="text" placeholder="请输入身高" />
但是运行之后发现无法输入任何东西,包括字母、符号、数字(后来实验发现,输入了汉字之后可以输入符号和数字,这个暂时未发现原因)。那么问题就来了,肯定是js部分的问题了。当时我就猜大概是做了限制,但是当时我还是比较相信同事写的代码的。我就面对着几个js文件一个一个的看,一个几千行行代码,知道我看到了下面这段代码:
$("input[type='text']").keypress(function (e) {
if (!String.fromCharCode(e.keyCode).match(/[0-9\.]/)) {
return false;
}
})
虽然当时没验证这段代码的情况,但是直觉告诉我找到原因了。我把这段代码复制出来还原了一下,大概意思就是所有的文本输入框在keypress事件触发这个函数,使用正则验证输入的情况,只能输入小鼠和小数点。但是当运行的时候问题出现了,bug出现了,那么问题找到了,就是这四行代码导致的,在那堆js代码中去掉这四行之后就没有了问题。
之后我研究出错的原因时发现,e.keyCode在谷歌时正常显示,但是在火狐浏览器下就会出现问题了:
|
谷歌浏览器 |
火狐浏览器 |
IE11浏览器 |
|
|
按键“a” |
keydown:keyCode为65,charCode为0 keypress:keyCode为97,charCode为97 keyup:keyCode为65,charCode为0 |
keydown:keyCode为65,charCode为0 keypress:keyCode为0,charCode为97 keyup:keyCode为65,charCode为0 |
keydown:keyCode为65,charCode为0 keypress:keyCode为97,charCode为97 keyup:keyCode为65,charCode为0 |
| 按键“1” |
keydown:keyCode为49,charCode为0 keypress:keyCode为49,charCode为49 keyup:keyCode为49,charCode为0 |
keydown:keyCode为49,charCode为0 keypress:keyCode为0,charCode为49 keyup:keyCode为49,charCode为0 |
keydown:keyCode为49,charCode为0 keypress:keyCode为49,charCode为49 keyup:keyCode为49,charCode为0 |
| 按键“Backspace” |
keydown:keyCode为8,charCode为0 keypress未触发 keyup:keyCode为8,charCode为0 |
keydown:keyCode为8,charCode为0 keypress:keyCode为8,charCode为0 keyup:keyCode为8,charCode为0 |
keydown:keyCode为8,charCode为0 keypress为触发 keyup:keyCode为8,charCode为0 |
那么问题就找到原因了,通过String.fromCharCode(e.keyCode)是无法做到兼容火狐浏览器返回按键值,因为当输入数字和字母时,其keyCode都为0。
因此,我修改了一下这个代码:
$("input[type='text']").keypress(function (e) {
var code = e.charCode || e.originalEvent.charCode;
if (code != 0) {
if (!String.fromCharCode(code).match(/[0-9\.]/)) {
return false;
}
}
})
originalEvent是jquery对原生event属性的封装。“code != 0”这个判断是在火狐浏览器下对是否按键为“Backspace”的判断,如果没有这个判断,会导致Backspace键无法使用,无法删除这个情况的发生。
谈限制输入框输入类型
其实无论是使用哪种方式来限制输入框的输入的类型,都离不开keyup、keypress、keyup和比较少见的textInput四个事件来触发。其中,前三个为各个浏览器共同支持的,而textInput仅有IE9+,Safari和Chrome,这也正式比较常见的浏览器(或其内核)。前三个事件为键盘事件,最后一个为文本事件。其触发的顺序为keydown(按键按下)——>keypress(按键值插入文本)——>textInput(按键值插入文本)——>keyup(按键弹起)。textInput和keypress的发生很相似,但二者还是有区别:任何可以获得焦点的元素都可以触发keypress事件,但只有可编辑区域才能触发textInput事件。textInput事件只会在用户按下能够输入实际字符的键时才会触发,而keypress事件则在按下那些能够影响文本显示的键时也会触发(比如退格键)。
在实际的操作中,我们会发现在输入中文的时候,只用按键事件对其进行触发限制输入框的操作体验非常不好。比如上面的代码,只在keypress事件触发限制,当我们输入法切换在中文时,按下字母之后按空格键或者“shift”键,会发现我们的限制失效了。

原生js
因此为了更好的体验,我们需要更多的事件触发限制,达到我们的目的。因此,我们应在触发keypress后在对即将插入文本框的值进行一边过滤。就拿上文的条件只能输入数字和小数点来说,我们需要在textIput事件发生时判断一下文本框的value值,使用正则进行一下过滤。代码如下:
var EventUtil = {
addHandler: function (element, type, handler) {
if (element.addEventListener) { //DOM2级
element.addEventListener(type, handler, false);
} else if (element.attachEvent) { //DOM1级
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = handler; //DOM0级
}
},
removeHandler: function (element, type, handler) { //类似addHandler
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else if (element.detachEvent) {
element.detachEvent("on" + type, handler);
} else {
element["on" + type] = null;
}
}
}
var textbox = document.getElementById('input');
EventUtil.addHandler(textbox, 'textInput', function (e) {
e.target.value = e.target.value.replace(/[^0-9\.]/g, '')
})
利用事件监听把绑定textIput事件,当触发时再对其value过滤一下。结果还是不错的:

但是在上文提到过,textInput属性对火狐浏览器无兼容,因此,我们就需要使用keyup对其进行代替(但效果不好):
textbox.onkeyup=function (e) {
e.target.value = e.target.value.replace(/[^0-9\.]/g, '')
}
附完整代码,原生js实现:代码地址。
Vue的自定义指令
简单少量的input我们可以使用双向绑定后,watch到变化进行限制,如下:
<input id="ipt" type="text" v-model="iptVal"/>
<script>
var qwe=new Vue({
el:'#ipt',
data(){
return{
iptVal:''
}
},
watch:{
iptVal(val){
this.iptVal=val.replace(/[^0-9\.]/g, '')
}
}
})
</script>
但是,当面对大量的input输入框,我们更向往用简单的方式去解决,甚至简单到只写一个指令(比如v-limit)就可以。这样,我们就需要用到自定义指令的知识(可参考我的博客《Vue的土著指令和自定义指令》)。
这个value是随着输入不断更新的,因此,我们需要选用update这个钩子函数:
Vue.directive('limit', {
update: function (el) {
el.onkeypress = function (e) {
var code = e.charCode;
if (code != 0) {
if (!String.fromCharCode(code).match(/[0-9\.]/)) {
return false;
}
}
}
el.addEventListener('textInput', function (e) {
e.target.value = e.target.value.replace(/[^0-9\.]/g, '')
})
el.onkeyup = function (e) {
e.target.value = e.target.value.replace(/[^0-9\.]/g, '')
}
}
})
此时,调用的方式特别简单,只需要增加“v-limit”这个指令即可。
<input id="ipt" type="text" v-model="iptVal" v-limit />
附完整代码,基于Vue的自定义指令的实现:代码地址。
从一次输入框无法输入的bug,谈如何限制输入框输入类型的更多相关文章
- react输入框输入中文bug
一般来说,react上我们都会用change事件去处理input的输入,但这样就导致一个问题,在输入中文的时候,我们还没输入完成就会触发change事件,这样显然不是理想状况. 那么,怎么解决这个问题 ...
- 控制 input 输入框不能输入中文,即不能在输入框中使用输入法
设置输入框的样式,代码如下 <span style="font-size:18px;"><input type = "text" id = & ...
- 小问题总结:鼠标点击到输入框(input)里的时候,输入框的提示消失,鼠标再移开,输入框提示出现
问题如标题: 鼠标点击到输入框(input)里的时候,输入框的提示消失,鼠标再移开,输入框提示出现.如图所示: 做法如下: <input type="text" name ...
- input标签type为number时,输入小数,在Firefox浏览器上输入框标红的问题
问题一:firefox 下 默认情况 <input type="number"> 只允许输入整数,输入小数时会报错,输入框被标红 这时候可以添加参数 step=&q ...
- ext当表单中的输入项为必填时,输入项label后显示红色的*
form表单里,当输入项为必填项时,需要将对应item的allowblank属性设置为true,如果item的label后面自带红色的*,表单中哪些输入项是“必填”,哪些输入项是“非必填”,一眼望去清 ...
- HDU 3306 Another kind of Fibonacci(矩阵+ll超时必须用int&输入必须取模&M必须是int类型)
Another kind of Fibonacci [题目链接]Another kind of Fibonacci [题目类型]矩阵+ll超时必须用int&输入必须取模&M必须是int ...
- 【bug】安卓浏览器键盘输入改变弹出层的定位
bug描述 在安卓浏览器中,有一个在页面底部的弹出层表单,样式如下: .popup { position: absolute; bottom: 0; } 当在这个弹出层输入内容,键盘自动弹出,弹出层的 ...
- input输入中文时,拼音在输入框内会触发input事件的问题。
问题描述: 监听文本输入框的input事件,在拼写汉字(输入法)但汉字并未实际填充到文本框中(选词)时会触发input事件,如图: 需要完成的需求就是在输入阶段不触发input中的事件,选词之后文字落 ...
- input、textarea等输入框输入中文时,拼音在输入框内会触发input事件的问题
监听文本输入框的input事件,在拼写汉字(输入法)但汉字并未实际填充到文本框中(选词)时会触发input事件,如图: 但是在很多情况下,只需要输入到输入框的中文字符. 解决办法: 通过查阅资料得知在 ...
随机推荐
- FFT && 复数重载
复数重载 与 FFT 1.复数重载: 重载了复数的运算,即重载了复数的加减乘以及赋初值. struct Complex{ //复数的重载 double r,i; IL Complex(){r = 0; ...
- MySQL性能调优与架构设计
1.Scale(扩展):从数据库来看,就是让数据库能够提供更强的服务能力 ScaleOut: 是通过增加处理节点的方式来提高整体处理能力 ScaleUp: 是通过增加当前处理节点的处理能力来提高整体的 ...
- Solidity by Example详解 - Voting
Example地址:https://solidity.readthedocs.io/en/develop/solidity-by-example.html#voting Voting程序的功能: 这个 ...
- 【noip模拟】最小点覆盖
Time Limit: 1000ms Memory Limit: 128MB Description 最小点覆盖是指在二分图中,用最小的点集覆盖所有的边.当然,一个二分图的最小点覆盖可能有很 ...
- jQuary学习の三の效果展示
一.隐藏显示 1.$(selector).hide(speed,callback);2.$(selector).show(speed,callback); 可选的 speed 参数规定隐藏/显示的速度 ...
- 精解Mat类(一):基本数据类型-固定大小的 矩阵类(Matx) 向量类(Vector)
一.基础数据类型 1.(基础)固定大小矩阵类 matx 说明: ① 基础矩阵是我个人增加的描述,相对于Mat矩阵类(存储图像信息的大矩阵)而言. ② 固定大小矩阵类必须在编译期间就知晓其维 ...
- 13.C++-静态成员变量、静态成员函数
首先回顾下成员变量 能通过对象名能够访问public成员变量 每个对象的成员变量都是专属的 成员变量不能在对象之间共享 再来讲讲类的静态成员变量 介绍 静态成员变量属于整个类所有 静态成员变量的生命期 ...
- 虚拟机安装CentOS6.3及常见问题总结
学Linux的同学大多数开始是使用的是Ubuntu或者red hat,red hat虽然安装不需要收费,但是服务是收费的,下面我就讲讲怎么用虚拟机安装CentOS6.3,其他Linux的安装可以参考这 ...
- jdk7u79linuxx64.tar.gz下载
jdk1.7下载: 百度云盘链接:https://pan.baidu.com/s/1cQFLnS 密码:wdek
- 谁能用通俗的语言解释一下什么是 RPC 框架?
转载自知乎:https://www.zhihu.com/question/25536695 知乎上很多问题的答案还是很好的,R大就经常在上面回答问题 关于RPC你的题目是RPC框架,首先了解什么叫RP ...