LimeJS 用來開發 HTML5 的小工具或小遊戲,基本上算是夠用。不過,從2012年開始應用以後,在行動載具上,尤其是 iOS 上,一直有兩大困擾:聲音的播放及輸入文字元件的控制。前者除了 iOS 的限制,基本上應該已經可以用自己寫的程序來克服了;後者則可能因為當初 LimeJS 的開發者,設計的目標是給開發遊戲使用,對取得鍵盤輸入可能比較沒有測試完整,到這兩天,花了不少時間、費了不少眼力,稍有眉目。
之前在「國字注字筆順練習工具」中,為了取得使用者輸入要練習的字串,以 input 元件讓使用者輸入,電腦上沒什麼問題,一到行動載具上,按了 input ,裡面卻不會出現游標及叫出虛擬鍵盤,後來是幫 input 設定了 touchstart 的事件,把 input.focus(); 寫在裡頭;另一個問題則是無法控制在 input 中的游標位置,只好利用 touchstart、touchmove和touchend去設定選取的範圍,很鱉的解決問題。
這兩天為了解 div 設了 contenteditable=true 以後,無法出現游標的問題,好好的研究一下問題到底出在哪裡?因為,當我不是利用 LimeJS 時,所有的一切都很正常的,很明顯,並不是 iOS 的 Safari 在作怪,問題就是由 LimeJS 引發的。
preventDefault
LimeJS 基本上有兩個地方在干擾:
首先,我為了解決在行動載具上,拖曳的動作會連動的移動了整個畫面,所以參考了別人的做法,在程式中幫 document 的 ['touchstart', 'touchmove', 'touchend'] 三個事件,加上了 preventDefault()。這個程序大大地影響我沒有自訂這三個事件觸發程序的物件。我以為所有物件都會按照瀏覽器的預設動作,事實上已經都被跳掉了。
其二,觀察 LimeJS 原始碼 lime/src/dirctor.js 中,有底下的幾行:
goog.events.listen(this, ['touchmove','touchstart'],
function(e) {e.event.preventDefault();}, false, this);
// todo: check if all those are really neccessary as Event code
// is much more mature now
goog.events.listen(this, ['mouseup', 'touchend', 'mouseout', 'touchcancel'],
function() {},false);
LimeJS 的大管家「lime.director」也是對針手指的觸控進行了改變預設動作的處理。
在行動裝置上,對以手指觸控的遊戲來說,前兩項都是必備的;但是對於有以鍵盤輸入的程式來說,則是很大的困擾。
那怎麼解決兩方的需求呢?
只好直球對壘了!目前的做法是修改高層有加上 preventDefault() 的程序,加上一個全域的變數來判斷事件觸發時,要不要執行 preventDefault()。例如,我加入了一個名為「preventDefaultEnabled」的全域變數,然後修改了 director.js 中的內容為:
// helper function to run preventDefault, add by gsyan
function lime_preventDefault(e) {
if(typeof(preventDefaultEnabled)=='undefined' || (typeof(preventDefaultEnabled)!='undefined' && preventDefaultEnabled)) {
e.event.preventDefault();
}
}
goog.events.listen(this, ['touchmove','touchstart'], lime_preventDefault, false, this);
也就是,當 preventDefaultEnabled 為 true 時,才會執行 preventDefault() ,沒有設定 preventDefaultEnabled 或是為 false 時,則維持 LimeJS 的原始設計。
當我進入需要以鍵盤輸入資料的程序時,就加一行:
preventDefaultEnabled = false;
而不需要再輸入後,就改加這一行:
preventDefaultEnabled = true;
經過這樣處理,在行動裝置輸入文字時,游標的控制就能比較正常。
focus
在 LimeJS 的框架中,行動裝置取得文字還有另一個問題,無論是 input (text type)、textarea 或是設了 contenteditable=true 的元件,它們都「只看得到,吃不著!」,拼命用手指戳,虛擬鍵盤硬是不出來!運氣好一點,偶能出現。
如果是 input 或是 textarea ,前面提到「國字注音筆順練習」工具中,是在 input 或是 textarea 的 touchstart 事件中,讓它去觸發 input 或 textarea 的 focus,保證沒問題。
至於 contenteditable 的 div ,首先,它的 style 中要設定「-webkit-user-select: text」,而它裡面的 children 的 style設為「-webkit-user-select: auto」。 focus 的部份可以比照 input 和 textarea,利用 toucshstart 或 touchend 來觸發,不過,我試了一下,似乎放在 touchend 比較順暢。
走了不少冤枉路,LimeJS 框架下,行動載具取得文字輸入的結果,總算是比較順暢些了。接下來,有空就要將以前的程式叫出來,好好的讓它們回到正軌!
沒有留言:
張貼留言