前言
最近產品需要做不少輸入框,產品想要的互動效果是:使用者可以輸入中英文,隨著使用者輸入能即時顯示已經輸入的字元個數,當超過數量限制時輸入框邊框變紅,同時給使用者提示資訊。
這互動聽起來沒啥問題,技術實現上似乎也沒啥痛點。但是當我實現出來以後遇到中文IME就有坑了。
怎麼個坑呢,且看下文~~
即時監測輸入框內容長度所遇到的坑使用 oninput事件來監聽
使用這個oninput事件的好處有2個:
當使用者通過右鍵複製改變輸入框內容時,可以監聽到;
只有在輸入框內容發生變化時才會觸發此事件,比如使用者按下方向鍵、control/shift 等這些控制字元鍵時此事件是不會觸發的;
當你輸入英文字元或者數字時效果完美,甚至在你正常輸入中文時也效果完美。但當你非正常輸入中文時就出現 bug 了。非正常輸入是怎樣的呢?看下面這張樣本圖:
看到了嗎,在這種中文輸入方式下,其實使用者還沒有輸入他想輸入的中文,只是輸入了幾個拼音,但 input 事件被觸發了,而且監聽到的輸入框value居然是d'd'd,不單單是拼音字元,還包括了分隔的點。假如輸入框內容長度被限制為不超過5,那麼在截圖這種情況下,就會提示使用者字元長度超過限制!。這樣的互動效果當然不是產品想要的。
使用onkeydown/onkeypress/onkeyup事件來監聽
這幾個事件的缺點是無法監聽右鍵複製而來的輸入內容,但是否也會存在與input事件一樣的問題呢?
我做了幾個實驗,發現keydown、keyup都會遇到和 input一樣的問題,但keypress沒有這個問題,因為在中文輸入狀態下,keypress不會觸發,不單是你輸入拼音的過程中不會觸發,等你選中所要輸入的中文如“對對對”後也不會觸發。那麼當輸入“對對對”後雖然超過了字元限制但無法給出字元長度超過限制!的提示。
折中解決方案
要想做到即時監測內容長度,又想保證中文IME狀態下沒有 bug,我折騰了好久最後發現 臣妾做不到呀!(要是哪位豪傑找到了,一定要告訴我呀~~)。
所以最後犧牲了下使用者體驗,找到了一個折中的方式:輸入框失去焦點時(即blur),或者使用者輸入斷行符號鍵時才進行內容長度的檢測。當然如果發現輸入框內容超過限制,要將游標停留在輸入框內,方便使用者進行修改。
哎,一說到使用者輸入斷行符號鍵時才進行內容長度的檢測又得說說以前栽的坑了
輸入框中如何檢測輸入了斷行符號鍵
其實這是一個很常見的互動,比如修改名稱時支援使用者輸入斷行符號後直接儲存、登入時支援使用者輸入斷行符號後直接登入。但其中要小心的坑是:**中文IME下按斷行符號鍵來輸入英文字元**。
中文IME下按斷行符號鍵來輸入英文字元的過程舉例:
比如我要輸入帳號進行登入,我的帳號是全英文的,我當前處於中文IME,但我懶得切換IME,於是我就直接敲了我的帳號(全英文字元),這時搜狗IME給我提示了一大串中文,然後我按了個斷行符號,輸入框就輸入了我想要的英文字元。
在這種情況下,使用者雖然輸入了斷行符號鍵,但使用者按下斷行符號鍵只是想在中文IME下輸入英文字元而已,這個斷行符號鍵並不是我們想要監聽的斷行符號鍵。那麼怎麼排除這種情況下的斷行符號鍵呢?
一般來說監聽斷行符號鍵我們會用keydown事件或者keyup事件,實現代碼如下所示。那麼是否這兩種方法都能過濾掉我們不想監聽的斷行符號鍵呢?
//方法一:使用 keydown 事件input.onkeydown = function(e){ if(e.keyCode == 13){ //使用者輸入的是斷行符號鍵 //做相關操作 }}//方法二:使用 keyup 事件input.onkeyup = function(e){ if(e.keyCode == 13){ //使用者輸入的是斷行符號鍵 //做相關操作 }}
經過實驗發現:使用keydown是可以成功過濾的,但使用keyup不能。
那麼我們來看看為什嗎?
是因為在keydown事件中:中文IME狀態下輸入的斷行符號鍵,檢測的 keyCode為 229 而不是13;單純輸入一個斷行符號時,keyCode才是13。
而在keyup事件中:中文IME狀態下輸入的斷行符號鍵,檢測的 keyCode是13;單純輸入一個斷行符號時,keyCode也是13。
下圖是我列印在 console 中的結果:(程式碼範例見這裡)
結語
關於輸入框涉及到的幾個事件:keydown/keyup/keypress/input/change
查看這裡:http://www.jb51.net/article/21237.htm