最近很久沒有更新博客了,不是沒有東西寫,而是沒有時間寫。公司項目上事情比較多,又在工會謀了份差事;家里房子裝修,盡管有老爸盯着,但很多時候還是要自己跑來跑去。所以有時候有了寫博客的想法,卻老是坐不下來細細寫。這些就算為自己這段時間的荒廢找個小小的借口吧。
其實最主要的問題還是在於自己對博客的定位。之前一直想每篇博客都盡量找到一些比較好的主題,寫的比較詳細,這樣看起來比較專業。但是這樣要求的話,每一篇就要花狠多時間准備,很多時間編寫,無形中也給自己帶來了很多壓力。這也是久久沒有動筆的一個主要原因。后來在看很多牛人的博客的時候,發現他們也經常放一些小的但是很有用的東西在博客上。都是平時開發的時候遇到的小問題和解決的過程。這樣的記錄其實並不需要花太多的時間,而且能夠鞏固自己對知識點的掌握,也便於以后再次查閱。於是我覺得這樣的方式挺好的,尤其是比較忙的時候,這樣短小精煉的博客,同樣能夠給自己帶來不少的長進,也能促進自己勤寫博客的習慣養成。
閑話就講到這里,接下來就進入今天的主題:使用中文輸入法時,對鍵盤事件的處理。
問題的起源是這樣的:組里有個同事發現現有項目上的一個自動補全的輸入框不響應中文輸入。英文輸入的時候,超過兩個字就開始向后台查詢復合條件的選項。但中文輸入的時候,在輸入法上不管輸入多少字,輸入框沒有任何反應,按了空格或者回車后,字進入了輸入框,依然沒有能夠出發補全的功能。 於是這個問題就到了”前端專家“我的手里。
如何入手呢,一開始當然是看現象。 發現中文輸入的時候,打出來的字都是在輸入法的框里,於是猜想鍵盤事件都被輸入法給截獲了。但讓我不解的是,為什么當字被輸入到輸入框里,還是沒有反映。我第一反映是到google看輸入框。於是分別打開chrome,firefox,ie看現象。
首先是Chrome,表現是最完美的,在輸入框中輸入中文的時候,輸入的拼音在中文被輸入之前填寫在輸入框里,匹配的內容應該是根據輸入框里的英文字母進行匹配,所以令人很滿意。

其次到了firefox,從下圖中我們可以看到。當打開中文輸入法打字的時候,並沒有任何文字被輸入到輸入框中,所以也就沒有任何匹配項出現。之后當按了回車或者空格,將文字輸入到輸入框中之后,才會有響應的匹配項顯示。

再來看一下IE,結果和firefox一樣,輸入法打開的時候,也沒有內容被捕獲和匹配。

看完這三個瀏覽器的現象,大概證實了自己的猜想,輸入框捕獲了一些鍵盤事件,從而導致瀏覽器無法獲取用戶輸入進行匹配。但當內容被填入輸入框的時候,匹配被觸發。 接下來一個很自然的想法,是不是onchange事件出發了匹配函數。於是自己開始動手試驗:
寫了一個最簡單的例子,input box分別綁定onchange,onkeydown,onkeyup,onkeypress事件,查看事件被出發的情況:
1 <html> 2 <head> 3 <script type="text/javascript"> 4 function onChange(e){ 5 console.log("onchange!"); 6 } 7 function onKeyDown(e){ 8 console.log("onkeydown"); 9 } 10 function onKeyUp(e){ 11 console.log("onkeyup"); 12 } 13 function onKeyPress(e){ 14 console.log("onkeypress"); 15 } 16 </script> 17 18 </head> 19 20 <body> 21 <input type="text" onchange="onChange()" onkeydown="onKeyDown()" onkeyup="onKeyUp()" onkeypress="onKeyPress()"/> 22 </body> 23 </html>
然后開始用各個瀏覽器進行測試:首先是英文輸入狀態下
| 普通按鍵 abc | alt.shift,ctrl | ESC | Backspace | Enter | ||
| Chrome | onkeydown, onkeypress, onkeyup |
onkeydown, onkeyup |
onkeydown, onkeyup |
onkeydown, onkeyup |
onkeydown, |
|
| Firefox | onkeydown, onkeypress, onkeyup |
onkeydown, onkeyup |
onkeydown, onkeypress, onkeyup |
onkeydown, onkeypress, onkeyup |
onkeydown, onkeypress,(當value發生變化的時候) onchange, onkeyup |
|
| IE10 | onkeydown, onkeypress, onkeyup |
onkeydown, onkeyup |
onkeydown, onkeypress, onkeyup |
onkeydown, onkeyup |
onkeydown, onkeypress, onkeyup |
從上面的表格中可以看出,不同的瀏覽器對不同的按鍵觸發的事件還是有所差別的。尤其是IE,按回車的時候不會出發onchange事件。
此外所有的瀏覽器,在onblur的時候,如果input的value發生了變化,都會觸發onchange事件。但是在輸入的過程中,onchange事件並不回被觸發,於是否定了我自己的對於onchange事件觸發查詢的猜想。
接下來是在使用中文輸入法的時候觸發的事件列表
| 普通輸入abc | 空格,填入內容 | ||
| Chrome | 每次按鍵 onkeydown, onkeyup |
onkeydown, onkeyup |
|
| Firefox | 只在第一次按鍵時觸發 onkeydown |
onkeyup | |
| IE10 | 每次按鍵 onkeydown, onkeyup |
onkeydown, onkeyup |
|
從上面的表中可以看出,如果想在用戶輸入過程中,通過onkeydown或者onkeyup事件來捕獲用戶的輸入,並且觸發匹配調用是不太可行的,尤其是在firefox上,用戶的鍵盤事件根本沒有辦法立刻獲取。所以我們也就可以理解,為什么google的搜索框,在firefox中,也只能等待中文內容被天津輸入框之后才能進行匹配搜索。
但是對於IE,依然能夠獲得keydown和keyup事件,那就夠獲得keycode,自然研究能夠知道用戶按了什么鍵,通過用戶按鍵進行匹配應該也是可以做到的。為什么ie上對中文輸入的反映與firefox是一樣的呢。
繼續搜索才發現,原來在中文輸入框的情況下,鍵盤事件並不能傳遞真實的用戶按鍵keycode。於是對代碼進行修改,加入了keycode和charcode的輸出:這里還遇到了firefox和ie對event參數的兼容性問題,前台開發真是不易啊。
1 <html> 2 <head> 3 <script type="text/javascript"> 4 function onChange(){ 5 console.log("onchange!"); 6 } 7 function onKeyDown(e){ 8 e = e || window.event; 9 console.log("onkeydown" + " keyCode:"+e.keyCode+" charCode:"+e.charCode); 10 } 11 function onKeyUp(e){ 12 e = e || window.vent; 13 console.log("onkeyup" + " keyCode:"+e.keyCode+" charCode:"+e.charCode); 14 } 15 function onKeyPress(e){ 16 e = e || window.event; 17 console.log("onkeypress" +" keyCode:"+e.keyCode+" charCode:"+e.charCode); 18 } 19 </script> 20 21 </head> 22 23 <body> 24 <input type="text" onchange="onChange()" onkeydown="onKeyDown(event)" onkeyup="onKeyUp(event)" onkeypress="onKeyPress(event)"/> 25 </body> 26 </html>
各個瀏覽器的測試結果如下:
| a | ESC | 中文輸入法a | 中文輸入法接着按b | 空格,填入中文內容 | |||
| Chrome | |||||||
| Firefox |
onkeydown keyCode:65 charCode:0
onkeypress keyCode:0 charCode:97
onkeyup keyCode:65 charCode:0
|
onkeydown keyCode:27 charCode:0
onkeypress keyCode:27 charCode:0
onkeyup keyCode:27 charCode:0
|
onkeydown keyCode:0 charCode:0 | 沒有事件 | onkeyup keyCode:32 charCode:0 | ||
| IE10 | onkeydown keyCode:65 charCode:0 onkeypress keyCode:97 charCode:97 onkeyup keyCode:65 charCode:0 |
onkeydown keyCode:27 charCode:0 |
onkeydown keyCode:229 charCode:0 |
onkeydown keyCode:229 charCode:0 |
onkeydown keyCode:229 charCode:0 |
這里有人可能會對keyCode和charCode產生好奇。我也是寫這篇博客的時候才了解到這個知識點:keyCode表示按下鍵的數字代碼,也叫鍵碼,charcode表示按鍵的Unicode,也叫字符編碼。這里有一篇文章介紹都比較詳細,大家可以具體去看一下:http://blog.sina.com.cn/s/blog_65c2ec5e0101blj6.html
本文的重點是中文輸入,大家可以看到,在chrome和ie中,使用中文輸入法輸入的時候,所有的keydown事件,keycode都是229,keyup事件的keycode表示正確。因此通過對keyup事件的捕獲,應該能獲取用戶的按鍵情況。但是對於Firefox,只能等到用戶按空格或回車將輸入的內容填入框中,才能捕獲keyup事件。然后通過輸入的內容來進行匹配查詢。
所以這個中文輸入法自動匹配問題的最終解決方案也比較明顯了:捕獲keyup事件,然后通過輸入框里的內容進行匹配查詢。
查看原有的code,果然只對keydown和keypress(針對opera)事件進行了捕獲,而沒有用到keyup,所以修改的內容就是將keydown事件改為keyup事件。
一個小小的中文輸入問題需要這么多的搜索和調試才能完美解決,而且這里只對chrome,firefox,ie做了支持,如果需要加上opera,safari,需要的工作可能更多。但相信這些問題碰到一個少一個,記錄下來也希望能為別人帶來一些便利。同時也盼望着將來各瀏覽器廠商之間規范的統一和相互兼容,讓前端工程師能有更加順暢的開發過程。
