上週臨近週末休息的時候,一個同事跑過來了,對我說:「阿倫啊,有一個頁面出問題了,火狐瀏覽器全部的input都無法輸入了。」我一聽,是否是你給加了什麼屬性,讓input輸入框只讀了啊。看了一下代碼,很正常的一個輸入框,而且CSS寫的也很正常。html
<input id="ipt-message" type="text" placeholder="請輸入身高" />
可是運行以後發現沒法輸入任何東西,包括字母、符號、數字(後來實驗發現,輸入了漢字以後能夠輸入符號和數字,這個暫時未發現緣由)。那麼問題就來了,確定是js部分的問題了。當時我就猜大概是作了限制,可是當時我仍是比較相信同事寫的代碼的。我就面對着幾個js文件一個一個的看,一個幾千行行代碼,知道我看到了下面這段代碼:jquery
$("input[type='text']").keypress(function (e) {
if (!String.fromCharCode(e.keyCode).match(/[0-9\.]/)) { return false; } })
雖然當時沒驗證這段代碼的狀況,可是直覺告訴我找到緣由了。我把這段代碼複製出來還原了一下,大概意思就是全部的文本輸入框在keypress事件觸發這個函數,使用正則驗證輸入的狀況,只能輸入小鼠和小數點。可是當運行的時候問題出現了,bug出現了,那麼問題找到了,就是這四行代碼致使的,在那堆js代碼中去掉這四行以後就沒有了問題。git
以後我研究出錯的緣由時發現,e.keyCode在谷歌時正常顯示,可是在火狐瀏覽器下就會出現問題了:github
|
谷歌瀏覽器瀏覽器 |
火狐瀏覽器函數 |
IE11瀏覽器post |
按鍵「a」this |
keydown:keyCode爲65,charCode爲0url keypress:keyCode爲97,charCode爲97spa 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」鍵,會發現咱們的限制失效了。
所以爲了更好的體驗,咱們須要更多的事件觸發限制,達到咱們的目的。所以,咱們應在觸發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實現:代碼地址。
簡單少許的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的自定義指令的實現:代碼地址。