寫於2017年11月1日,若有錯漏,歡迎斧正。javascript
原文css
在移動端H5頁面開發中,有時候會有一些數值輸入方面的需求。若是須要讓用戶比較方便地輸入小數、負數,最簡單的方式是使用number類型的input框,輸入時軟鍵盤會切換爲數字鍵盤方便輸入(ios是帶數字的全鍵盤,並容許1e5這類的表示方法)。可是在實際使用的時候會面臨一個問題,當輸入的內容不合法時,好比輸入了1...2
,此時input會設置本身的狀態爲invalid,並把value清空。咱們能夠在css中經過input:invalid
來爲此input設置輸入內容錯誤的樣式,而在js一端,咱們卻沒法知道用戶輸入的錯誤內容究竟是什麼。這個問題是dom自己的特性所置,與咱們採用的開發框架無關,無論咱們是使用angular、vue仍是react,當number類型的input中輸入不合法內容時,js就是沒有辦法知道錯誤內容是什麼,也就沒有辦法幫助用戶修正輸入錯誤。html
然而實際需求可無論這個,限制用戶輸入的數值範圍、小數點後精度、是否容許負數等等都是很常見的需求。那怎麼辦呢?最近看到一篇文章作了一個很迫不得已,但確實很華麗的嘗試:一個數字鍵盤引起的血案——移動端H5輸入框、光標、數字鍵盤全假套件實現。有興趣能夠看一下,這篇文章實現了一個假的鍵盤來處理這些邏輯。在很複雜的交互和視覺需求下,作一個假鍵盤也不失爲一個終極的解決方案。不過在我看來,處理數字格式、糾錯等問題倒能夠不用這麼麻煩,下面我就分享一下個人思路。vue
設置一個目標吧:java
雖然定了這麼多目標,歸根到底只要能獲得輸入框的輸入內容,剩下的就是簡單的字符串處理了。那麼如何能獲取輸入內容呢?個人方法是讓瀏覽器選中輸入框中全部的內容,而後獲取瀏覽器中選中的字符串,最後清除選中狀態。選中輸入框中的內容有兩種方法:react
input.select()
(HTMLInputElement.select());document.execCommand('SelectAll')
來全選輸入框中的全部內容(The selectAll command)。然而實際上類型的爲number的輸入框是不容許操做selectRange的,雖然能選中內容,獲取輸入框中信息,但我在清除選中狀態時遇到了問題(也許我代碼寫得不對),那麼採用第二種方法。獲取瀏覽器選中的字符串能夠用Window.getSelection().toString()
(Window.getSelection())。獲得實際輸入的內容後,咱們能夠進行一系列的邏輯判斷、數值更正。那麼最後怎麼再把正確的內容寫回input框中,同時清除選中狀態呢?方法也不少:ios
document.execCommand('copy')
和document.execCommand('paste')
(The copy command、The paste command);到這裏基本上所須要的準備工做都已經完成,試着實踐一下:git
<input type="number" id="input"/>
複製代碼
const input = document.querySelector('#input');
const format = /-?\d{0,5}(\.\d{0,2})?/;
let lastValue;
input.addEventListener('input', event => {
document.execCommand('SelectAll');
let text = window.getSelection().toString();
if (lastValue !== text) {
const match = text.match(format);
if (!match) {
text = '';
}
else {
text = match[0]
.replace(/^(-?)0+(\d)/, '$1$2') // 刪除多餘的前置0
.replace(/^(-?)\./, '$10.'); // 插入純小數的整數0
}
lastValue = text;
document.execCommand('insertText', false, text);
}
});
複製代碼
Demogithub