使用Javascript限制文本框只允許輸入數字


很多時候需要用到限制文本框的數字輸入,試過許多方法,都不太理想,遂決定自己實現一個來玩玩。

曾經使用過的方法

通過onkeydown事件來控制只允許數字:

<input onkeydown="return event.keyCode>=48&&event.keyCode<=57||event.keyCode>=96&&event.keyCode<=105" />

通過jQuery插件Masked Input:http://digitalbush.com/projects/masked-input-plugin/

通過jQuery插件MeioMask:https://github.com/fabiomcosta/jquery-meiomask

onkeydown事件控制起來相對比較麻煩,上面的簡化版很多鍵都沒有涉及到,操作體驗比較糟糕。

jQuery的兩個插件使用起來還是比較靈活的,能夠滿足大部分需要,但是在控制輸入長度上限制的很不靈活(或許是我沒有發現靈活的使用方式?)

具體實現方法

使用maskedInput里的一部分方法來提取光標位置

使用stackoverflow上提供的通用方法來處理鍵盤的敲擊:http://stackoverflow.com/questions/469357/html-text-input-allow-only-numeric-input

更新:參考http://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes上列出的keycode

然后再自定義兩個屬性來設置輸入的數字、小數長度:

  • data-numbers控制數字輸入的長度
  • data-decimals控制小數輸入的長度

最終全部代碼實現如下:

  function validateDigitsOnly(evt) {
      var e = evt || window.event,
        key = e.keyCode || e.which;

      if (
        // Backspace, Tab, Enter, Esc, Delete
        key == 8 || key == 9 || key == 13 || key == 27 || key == 46 ||
        // Ctrl + A
        (key == 65 && event.ctrlKey === true) ||
        // Home, End, 四個方向鍵
        key >= 35 && key <= 40) {
          return;
      }

      if (e.shiftKey || e.altKey || e.ctrlKey) {
        return false;
      }
      
      var el = e.target || e.srcElement,
        // 最大數字長度
        nl = parseInt(el.getAttribute("data-numbers")) || 15,
        // 最大小數長度
        dl = parseInt(el.getAttribute("data-decimals")) || 2,        
        val = el.value,
        // "." 位置
        dotIndex = val.indexOf("."),
        rng = caret.call(el),
        // 光標在"."左邊
        rLeft = rng.end <= dotIndex,
        // 光標在"."右邊
        rRight = rng.begin > dotIndex;
        
      if (
        // 數字   
        key >= 48 && key <= 57 ||
        // 數字鍵盤輸入的數字
        key >= 96 && key <= 105) {
        if (validateValue(dotIndex, val, rLeft, rRight, nl, dl))
          return;
        
        // 選中部分文本再做一次處理
        val = val.substring(0, rng.begin) + val.substring(rng.end);
        dotIndex = val.indexOf(".");
        if (validateValue(dotIndex, val, rLeft, rRight, nl, dl))
          return;
      }
      else if (
        // "."
        (key == 190 ||
        // 數字鍵盤上的 "."
        key == 110) &&
        // 允許輸入小數
        dl > 0) {        
        if (
          // 未輸入".", 且輸入的位置后面的小數位數未達到上限
          dotIndex == -1 && (rng.end == val.length || val.substring(rng.end).length <= dl) ||
          // 輸過".", 且選中部分文本包含"."
          dotIndex > -1 && rng.begin <= dotIndex && dotIndex < rng.end)
          return;
      }
      else if (
        // "-"
        (key == 189 || 
        // 數字鍵盤上的 "-"
        key == 109) &&
        // 光標在開始位置
        (rng.begin == 0 && 
        // 未輸入過"-"負號 或者 選中了開頭一段文本
        (val[0] != "-" || rng.end > rng.begin))) {
        return;
      }

      return false;
  }
  
  // 驗證輸入的值
  function validateValue(dotIndex, val, rLeft, rRight, nl, dl) {
    if (val[0] == "-") nl = nl + 1;//負號開頭多加一位
    if (
      // 未輸入過"."
      dotIndex == -1 && val.length < nl ||
      // 光標位置在"."之前
      rLeft && val.substring(0, dotIndex).length < nl ||
      // 光標在"."之后且未達到小數上限
      rRight && val.substring(dotIndex + 1).length < dl)
      return true;
    return false;
  }
  
  // 獲取光標位置
  function caret() {
    var begin, end;
    if (this.setSelectionRange) {
      begin = this.selectionStart;
      end = this.selectionEnd;
    } else if (document.selection && document.selection.createRange) {
      var range = document.selection.createRange();
      begin = 0 - range.duplicate().moveStart('character', -100000);
      end = begin + range.text.length;
    }
    return { begin: begin, end: end };
	}

 

使用方法

具體使用方法如下:

<input type="text" id="t1" />
<input type="text" id="t2" data-numbers="5" data-decimals="4" />
<script>
	document.getElementById("t1").onkeydown = validateDigitsOnly;
	document.getElementById("t2").onkeydown = validateDigitsOnly;
</script>

或者干脆寫在html里:

<input type="text" id="lwme_text_3" onkeydown="return validateDigitsOnly(event)" />

如果引入jQuery的話使用起來就更加簡單了:

<input type="text" class="digitsOnly" />
$(".digitsOnly").keydown(validateDigitsOnly);

一些需要額外處理的情況

對於使用右鍵菜單或者是菜單欄粘貼進來的需要額外處理;

有方法是直接訪問clipboardData來修改剪切板數據,但是可能會受權限困擾; 所以干脆直接通過onpaste事件來禁止粘貼比如:

document.getElementById("lwme_text_1").onpaste=function(){return false;};

此外還有oncut,oncopy來禁止剪切、粘貼

若只是單單禁用右鍵菜單,可以使用onmousedown方法:

    document.getElementById("lwme_text_1").onmousedown=function(e){
      if (e.button && e.button == 2 ||
        e.which && e.which == 3)
        return false;
    };

還有一種極端的情況:在網頁中選中文字並拖動到文本框內,或者是在文本框中選中文字並拖動,這都需要做額外處理

一種辦法是直接阻止body的ondragstart事件(體驗不是很好):

    document.body.ondragstart=function(){return false;};

直接加在body上用戶體驗不是很好,所以這種辦法不太可取,不過用來禁止文本框內的選中內容拖動還是比較不錯的辦法:

    document.getElementById("lwme_text_1").ondragstart=function(){return false;};

更好一點的辦法是在oninput事件里處理(ie6-8為onpropertychange事件),這樣用戶基本感覺不到文字閃動:

    document.getElementById("lwme_text_1").oninput=function(){
      if(isNaN(this.value))
        this.value = parseFloat(this.value) || "";
    };
    
    // ie 6-8
    document.getElementById("lwme_text_1").onpropertychange=function(){
      if(isNaN(this.value))
        this.value = parseFloat(this.value) || "";
    };

這個方法也可以用於處理粘貼的文本

在win8下,切換到微軟拼音可能會造成無法輸入,不知道其他系統或者其他輸入法有沒有這個問題(`~~`)

解決辦法是通過樣式style="ime-mode:disabled"來禁用輸入法,chrome瀏覽器不支持這個樣式則直接使用input type=number來控制

表單驗證還是必須品

使用了以上的方法,基本上能解決大部分出現的問題,但是為了防止未知情況的影響,還是有必要加上jQuery.validate之類的表單驗證來提供更多保障

結尾

這個方法雖然有些地方效率還不夠高,而且某些鍵盤key的還未處理,也不排除某些情況下可能失效,但是對於大多數情況下使用已經足夠了。

大家若有額外需要請自行修改,當然有更好的辦法也請分享(*^__^*)

PS:01.18更新了一些keyCode的判斷,以及錯把110寫成109≡(▔﹏▔)≡

PS:感謝評論的各位提供的方法

放到github以后慢慢完善

over


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM