從一次輸入框無法輸入的bug,談如何限制輸入框輸入類型

来源:https://www.cnblogs.com/lunlunshiwo/archive/2018/04/03/8705856.html
-Advertisement-
Play Games

bug的產生和修改 上周臨近周末休息的時候,一個同事跑過來了,對我說:“阿倫啊,有一個頁面出問題了,火狐瀏覽器所有的input都沒法輸入了。”我一聽,是不是你給加了什麼屬性,讓input輸入框只讀了啊。看了一下代碼,很正常的一個輸入框,並且CSS寫的也很正常。 但是運行之後發現無法輸入任何東西,包括 ...


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的自定義指令的實現:代碼地址


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1、去官網下載MySQL,https://dev.mysql.com/downloads/mysql/5.6.html#downloads 選擇redhat6 64bit 下載rpm bundle 2、將文件拷貝到centos,解壓 tar -xvf MySQL-5.6.39-1.el6.x86_6 ...
  • 從Google首席執行官埃里克·施密特(Eric Schmidt)首次提出“ 雲計算 ”(cloud computing)的概念到現在,雲計算已經走過了炒作期和實踐期,已經處於成熟期。同時,行業集中度也越來越高並呈逐漸加強的趨勢,目前業內大公司已經占據了整個市場的半壁江山。 Synergy Rese ...
  • 蘋果在關於後臺模式的文檔中稱:“這個配置項應該儘可能少的使用,而且最好只給那些提供通知服務的應用使用。如果有在後臺運行的替代方法,就應該使用替代方法。比如,如果應用能使用顯著位置變化介面來接受位置變動事件的話,就不要將應用註冊為需要在後臺監控位置變化的應用。 這個配置項可選的值有:audio,loc ...
  • 經過進兩周的持續發酵,Facebook5000萬用戶數據泄露事件,已讓其處在輿論的風尖浪口。對於手機APP泄漏用戶個人隱私問題,再次受到人們的關註。對於這個問題,你會怎麼看? 隱私,即不願公開的個人信息,前幾日,百度CEO李彥巨集在某論壇上說了一段引發爭議的話:“假如他們願意用隱私交換便捷性或者效率的 ...
  • 要瞭解TextView對文本的繪製,那麼就需要瞭解Paint.FontMetircs。 官方對該類的解釋是:Class that describes the various metrics for a font at a given text size., 意思是說,這玩意兒是繪製文本內容時存儲該文 ...
  • RxJava2已經推出有一年半的時間,由於之前RxJava已經在現有項目中廣泛使用,而RxJava2在除了很多命名外並沒有太多革新,所以相信有很多人跟我一樣都還沒有升級. 隨著老版本漸漸的失去維護,更重要的是有一定時間允許我來做這個遷移,其實棄老從新一直都是程式員的喜好. ...
  • 其中有一個不太規則的label: image.png image.png 這個label頂部的兩個角是圓角,底部的兩個角是直角,底部還有一個小三角。 思路 CAShapeLayer聯合UIBezierPath畫一個不規則的layer作為label.layer的mask。 具體實現 1.自定義一個繼承 ...
  • 自定義封裝UITableView,更加簡潔高效,無需為了實現delegate增加膠水代碼,自帶下拉刷新上拉載入控制項 "項目倉庫地址" 歡迎互相交流學習,問題交流群群號:296406818 如何開始 "項目技術特點" "安裝方法" "框架用法" 代碼結構 "GYTableBaseView.h" "GY ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...