移動Web之觸摸和指針事件詳解
本文詳細介紹了蘋果的觸摸事件和微軟的指針事件之間的不同,可以了解兩者間的差別。
針對觸摸和指針事件,W3C有相應的推薦標準。你可以在http://smashed.by/mwhb8 和 http://smashed.by/mwhb9 找到對應的標準。
雖然有這么兩個標準,但是W3C似乎正在從觸摸事件向指針事件遷移。制定觸摸事件標準的Web事件工作小組(Web Events Working Group)已經被解散,相關工作也停滯了。但是指針事件小組的工作仍然在進行,指針事件也正在成為標準。
谷歌和Mozilla正在實現指針事件,也許在你閱讀這篇文章的時候他們已經完成了。可參見Chrome的討論和Firefox的討論。
早在2007年,蘋果公司就發布了第一款真正支持觸摸屏的瀏覽器。這款瀏覽器會監控用戶的觸摸操作,并派發相應的事件。
除了指針事件的發明者微軟外,其他多數瀏覽器廠商復制谷歌或Mozilla的實現。這兩套事件是本章討論的主題。
乍一看,在指針事件上,IE又是那么“與眾不同”,但事實并不如你所想。
微軟在這方面提出了一個有趣的哲學觀點,我們將在后面詳細討論。在撰寫本書時,谷歌和Mozilla正在考慮著手實現指針事件。W3C也正在從觸摸事件過渡到指針事件。
在大多數方面,觸摸事件和指針事件是普通的JavaScript事件。當觸摸動作發生時,觸摸事件和指針事件被觸發。你可以為它們指定事件處理函數,它們的事件對象也提供了有用的觸摸相關的信息。觸控事件和傳統的鼠標、鍵盤事件之間有一些技術上的差異。 此外,出于兼容性的考慮,觸屏設備必須觸發鼠標事件,因為很多網站仍然依賴于它們。但是,在沒有鼠標的設備上觸發鼠標事件會發生什么事情呢?本章專門討論這些問題。
本章的其余部分在本質上更具有哲學性。隨著iPhone的推出,蘋果引入了一種新的交互模式:觸摸。 現在,觸摸、傳統鼠標、鍵盤三種交互模式并存。Web開發人員需要確保網站適應這三種交互模式。乍一看,觸摸事件和鼠標事件差不多。那它們之間有什么區別呢?我們真的需要為觸摸交互模式再設計一套事件嗎?
觸摸事件
我們先從觸摸事件開始講起,因為相比指針事件來說,瀏覽器對觸摸事件的支持更好一些。稍后,你將看到,指針事件是非常相似的。一共有4種觸摸事件:
- touchstart,在用戶的手指觸摸屏幕的瞬間觸發。
- touchmove,在用戶移動手指的過程中連續觸發。
- touchend,用戶的手指離開屏幕的瞬間觸發。
- touchcancel,其含義取決于瀏覽器。后面將會討論。
pointerdown、pointermove和pointerup事件在同一時刻觸發
這些事件得到了大多數觸屏瀏覽器的支持,但IE瀏覽器是一個例外。還有一些很古老的和不完善的瀏覽器也不支持,比如塞班Anna的默認瀏覽器。代理瀏覽器也不支持,因為這些事件不適用于代理瀏覽模式。其中的原因我們將會在“瀏覽器”一章討論。
touchcancel
我承認我不太明白touchcancel事件。touchcancel在觸摸序列被取消時觸發。但是這意味著什么完全取決于瀏覽器的實現:Chrome瀏覽器在用戶的手指離開屏幕的瞬間觸發touchcancel事件,但其他大多數瀏覽器則沒有。
幸運的是,我還沒有發現必須使用touchcancel的情景。貌似其他腳本和庫也幾乎沒有使用 touchcancel。有些代碼為了安全起見,把它等同于touchend。綜上所述,本章將忽略touchcancel事件。如果在某些情況下瀏覽器 沒有觸發touchend事件,導致一些奇怪的問題,你可以將touchend的處理函數綁定到touchcancel上。
手勢事件
除了觸摸事件,Safari瀏覽器在iOS上還實現了gesturestart、gesturechange和gestureend事件。IE瀏覽器也有一組類似的事件。手勢事件被定義為兩個或多個觸摸事件同時發生。
手勢事件存在兩個問題:一來,其他瀏覽器不支持。二來,它們根本沒什么用處。理論上,通過這套事件檢 測用戶的手勢聽起來很不錯,但實際上,你需要分析觸摸坐標、移動速度甚至加速度才能搞清楚用戶真正的意圖。所以我們不需要手勢事件,因為普通的觸摸事件已 經提供了同樣的信息。所以本章不再討論手勢事件。
其他事件
touchenter和touchleave
觸摸事件規范中曾經包含touchenter和touchleave事件,這兩個事件在用戶手指移入 或移出某個元素時觸發。但是這兩個事件從來沒有被實現。微軟有這兩個事件的替代事件,但是只有IE瀏覽器支持。某些情況下可以知道用戶手指滑入、滑出某個 元素是非常有用的,所以我希望這兩個事件可以重返規范。
縮放事件
我從2010年以來就一直呼吁加入縮放事件,但是至今也沒有人聽。盡管如此,能響應用戶縮放還是很有用的:比如你可以在用戶縮放后改變界面,或者只是收集縮放數據以得知頁面字號是不是過小。
實例
我們將用三個實例來對比觸摸、指針事件與鼠標鍵盤事件。通過對比引導你思考各種交互模式以及如何將以前基于鼠標交互的頁面遷移到基于觸摸交互,反之亦然。
下拉菜單
第一個實例絕對經典:下拉菜單。不管你是否喜歡,網上到處都可以見到下拉菜單。而且下拉菜單也是一個絕好的實例,因為它囊括了事件處理的方方面面。
傳統的下拉菜單是通過鼠標交互工作的。用戶將鼠標懸停在某個下拉菜單按鈕上,菜單彈出并展開。用戶移 開鼠標,菜單收起。下拉菜單也可以用鍵盤操作:用戶用Tab鍵將焦點移到下拉菜單按鈕上時,菜單展開。焦點離開時菜單收起。實現下拉菜單的鍵盤交互要比實 現鼠標交互困難些,但不是不可能。
傳統下拉菜單在onmouseover時打開,在onmouseout時收起
我們如何為下拉菜單增加對觸摸交互的支持呢?簡單地將mouseover替換為 touchstart,將mouseout替換為touchend是不管用的:手指點擊下拉菜單按鈕彈出菜單沒什么問題,但是如果用戶此時想點擊某個鏈 接,手指一離開屏幕,touchend觸發,菜單就收起了。顯然這是不行的。你也許會說,那我們在touchend的時候不要收起菜單好了。那問題又來 了:什么時候關閉它呢?
跨設備環境的最好解決方案是使用點擊事件。點擊展開菜單,而不是鼠標懸停時展開。點擊另一菜單項則會收起當前菜單。我們在本章后面會看到,點擊事件很安全。并且基于點擊的下拉菜單可以適用于鼠標和觸摸交互。
盡管如此,移動瀏覽器仍然需要與現實抗爭:網上仍然有成千上萬基于鼠標懸停的下拉菜單。幸運的是,下拉菜單是一個特殊的用例。蘋果公司在設計觸摸事件的時候已經考慮到了并且其他瀏覽器照搬了他們的實現。這點我們在本章后面會遇到。
拖放
與下拉菜單完全不同的一個實例是拖動和拖放。用戶在鼠標按下時選中一個元素,然后移動,最后松開鼠標將元素放在某個地方。最后腳本會計算放置點是否有效并根據計算結果做出處理。
將這個實現移植到基于觸摸的交互非常簡單:將mousedown替換為touchstart,mousemove替換為touchmove,mouseup替換為touchend就可以了。唯一的問題是如何確定事件的坐標。后面我們會講到。
這里的問題是鍵盤的可訪問性。如何讓用戶通過鍵盤移動可拖動元素?你可以將一個區域的元素設置成可以 通過鍵盤聚焦,一旦某個元素得到焦點,就開始監聽方向鍵。這在技術上并不困難,但是用戶體驗很差。這個問題基本上無法解決:拖放操作本身就是為鼠標和觸摸 交互設計的,無法在鍵盤上得到好的體驗。
為了滿足讀者的好奇心,這里有一段我很久以前寫的腳本,實現了鼠標、鍵盤拖放。鍵盤拖放有些反直覺。為這個腳本增加觸摸支持非常簡單,留作一個練習由讀者完成。
滾動層
在2011年時,我需要一個可以在所有設備上工作的水平滾動元素。那時候設備還沒有原生支持,仍需要腳本,所以我寫過一個。現在設備已經原生支持,那段腳本不再需要了。這點我們在CSS章節已經看到。不過這段腳本仍然是一個很有用的實例,所以我們假設仍然需要那段腳本。
寫這段腳本不是什么難事:在ontouchstart事件中計算滾動元素的當前位置,并初始化其他事 件處理函數;在ontouchmove事件中將元素移動相應像素的距離;在ontouchend中,運行一個函數來計算合理的減速,一旦被移動的元素停止 移動,這個函數結束。很簡單吧,我花了大概兩個小時。
非觸摸設備怎么辦呢?為了讓滾動層可以工作,我需要將觸摸交互翻譯成鼠標、鍵盤交互。鍵盤很簡單,只需監聽keydown事件,當用戶按下左/右鍵時滾動元素。這點可能不是那么容易發現,但是現在這個腳本算是正式支持鍵盤操作了。
鼠標設備怎么辦?從技術上來講,增加對mousedown、mousemove和mouseup事件的處理并不難,但是交互非常奇怪:用戶必須一直按下鼠標按鍵才能滾動元素。這種交互和拖放一樣,但是對于滾動層來說并不是那么直觀。
我可以用老式的滾動條箭頭:當鼠標移動到箭頭上時腳本開始工作。但是視覺上看,增加箭頭有些零亂。除此之外,當用戶觸摸或者使用鍵盤時還得隱藏箭頭。我沒有找到一種安全正確的方法(我們在后面會再次遇到這個問題),最終我并沒有支持鼠標交互。
事件和交互模式
在1996年,Netscape引入了鼠標事件和著名的鼠標懸停效果,廣受Web開發者的歡迎。之后 “可訪問性專家”指出,有些用戶沒有鼠標,而瀏覽器支持鍵盤事件。一些Web開發者聽取了意見,從此在他們的代碼中增加了對鼠標和鍵盤兩種交互的支持。蘋 果公司引入觸摸交互之后,就變成了三種。
Web開發者必須確保他們的網站可以在三種交互模式下正常工作。做到這點有時候很簡單,有時候卻很困難,不過都是必要的。不僅是為你現在的網站增加這些支持,你應該開始思考為UI元素增加對各種操作模式的支持。我希望上面的實例代碼可以教會你如何思考這類問題。
在未來,我們可能會有更多的交互模式,比如Xbox Kinect,它將身體動作轉換成屏幕動作。這樣你可以用你的手來控制屏幕上的指針。從技術角度來講,控制指針意味著將使用鼠標事件,但是從用戶的角度看這是一種新的操作模式。畢竟感覺上完全不同。
汽車、冰箱、可穿戴以及新興的設備都可能為用戶和Web開發人員帶來新的交互模式,比如doorclose(關門)事件。
思考交互模式和JavaScript事件帶來三個問題:
- 是不是每個交互模式都需要自己的事件?
- 已有的交互模式的事件在新設備上不再有意義時,是否需要繼續支持?
- 如何判斷設備支持哪種交互模式或用戶正在使用哪種模式?
目前來看,前兩個問題的答案是肯定的,第三個問題的答案比較復雜。但是,在將來,第一個問題的答案可能是否定的。再看看Kinect的例子:我們是發明全新的硬件事件,還是使用指針和鼠標事件呢?從技術上來講,無論用戶怎么移動,指針還是指針。
等價事件
目前每種交互模式都有自己的一套事件,但這并不意味著它們是完全無關且不同的。事實上,某些事件是等價的。下面的表格給出了這方面的情況。
等價事件
很顯然,觸摸動作序列:touchstart-touchmove-touchend和鼠標序 列:mousedown-mousemove-mouseup以及鍵盤序列:keydown-keypress-keyup很相似,這并不是巧合,因為這 三種交互模式都可以描述為start-move-stop。(所以我們不需要完全不同的事件,對不對?)
但是,有時候兩個操作模式很像,但第三個卻不。比如在下拉菜單的例子里,鼠標和鍵盤很像,而觸摸不同。在拖放實例中,鼠標和觸摸幾乎一致,但鍵盤非常不同。在滾動層的例子里,這三種操作模式完全不同。(所以我們還是需要不同的事件,對吧?)
最后是mouseover和mouseout的問題。focus和blur是它們的鍵盤模式的等價事件,但是觸摸模式沒有這樣的等價事件。就像我們在“CSS”一章看到的,在觸摸屏設備中不存在“懸停”。
觸摸事件的不同之處
可以看出,等價事件確實存在,這取決于上下文。但是觸摸、按鍵和鼠標事件并不完全相同。顯然,由于鍵盤是這三種交互模式中最與眾不同的,所以Web開發人員傾向于將注意力集中在鼠標與觸摸上。讓我們先來討論這二者的差異吧。
當鼠標指針移入某個元素,或者用戶按下某個鼠標按鍵時,系統可以立即判斷出應該觸發哪個事件。而對于 觸摸操作來說就不同了,觸摸操作可以引出不同的動作:在你的手指觸碰屏幕的瞬間,系統還無法判斷出你的意圖。你只是想輕觸(Tap)某個元素?還是想滾動 某個可滾動元素?亦或是想縮放?還是想雙觸(Double-Tap)?瀏覽器必須等待一定時間間隔才能做出判斷。這個時間間隔并不是非常短,而是一個可察 覺的間隔。這點在后面還會講到。
多個觸摸動作可以同時發生。這一點對鼠標動作來說是不可能的:一臺計算機只能有一個鼠標(指針)。通 常來說,多點觸摸不會帶來麻煩:大多數網站只支持單點觸摸。單點觸摸很容易用鼠標來模擬。即便是網頁中有兩個滑動條,它們之間也不會互相干擾。因為就算用 戶同時滑動它們,你也可以認為它們之間是相互獨立的。二者都可以很好地通過觸摸和鼠標進行操作。
當網站允許并需要多點觸摸時,情況就不同了。如果腳本將同時發生的多點觸摸翻譯成手勢、旋轉或者縮放動作,鼠標就無法模擬了。多點觸摸帶來的問題需要具體問題具體分析。但是你必須意識到這一點。
鼠標指針總是指著某一個像素,而手指觸摸會覆蓋很多像素點。通常,系統會從這些像素點計算出一個中心點作為觸摸事件的坐標。并且在touchstart和touchend之間給手指移動留有余地。但是后面會講到有些瀏覽器并沒有這么做。
觸摸事件是不連續的,而鼠標事件是連續的。當你將鼠標指針從元素A移動到元素B時,鼠標指針會不可避 免地掠過AB之間的元素。鼠標移動是連續的還意味著你可以通過腳本進行監控。觸摸操作就不同了,你可以放開元素A,抬起手直接去碰元素B。這正是我們在下 拉菜單實例里試圖支持觸摸事件時遇到的問題。下拉菜單設計之初就需要連續的事件,因為它是為鼠標環境而設計的。
觸摸事件比鼠標事件攜帶了更多的信息。比如,觸摸屏可以探測到用戶手指的溫度,觸摸區域的半徑,觸摸的壓力值。現在雖然沒有給出這些數據,不過將來很有可能給出。因為在IE的指針事件中,已經預留了一些對應的屬性。
不管怎樣,鼠標和觸摸雖然相似但又不完全相同。
能否合并觸摸事件與鼠標事件
我們發現,通常情況下鼠標事件和觸摸事件非常相似,但是二者還是有一些本質區別的。有了這個認識,我們就可以更好地理解微軟的指針事件,以及為什么會提出指針事件。
微軟認為沒有必要分出鼠標、觸摸兩種事件。不管是鼠標指針、手指(觸摸)還是觸控筆(也叫定位筆),統稱為指針,只要通過這些指針改變了些什么,就觸發指針事件。所以,下面是微軟版本的等價事件:
微軟給出的等價事件
現在我們有了兩種事件分類方式:鼠標、觸摸分離的蘋果版本;鼠標、觸摸整合的微軟版本。到目前為止, 只有IE支持微軟的版本。其他瀏覽器都支持蘋果版本。又如我們在前面看到的,Mozilla和Google正在考慮實現指針事件 (PointerEvent)。所以未來情況可能還會發生變化。
Google 之所以對指針事件感興趣,是因為它的Chromebook Pixel筆記本和微軟的Surface平板電腦一樣,都有觸摸屏和帶觸摸板的鍵盤。二者都支持鼠標和觸摸操作。如果這兩種事件能統一成一種,網站對它們的支持就會變得簡單很多。
微軟的Surface是一個觸屏平板電腦,你還可以外接一個帶觸摸板的鍵盤。在訪問網站時你可以在鼠標和觸摸之間切換。這種情況需要通過指針事件來處理。
我個人認為微軟的方案是個好主意。隨著時間的推移,越來越多的設備會同時支持鼠標和觸摸操作。所以指 針事件是超前意識。同時指針事件可以方便地擴展以支持其他操作,而不局限于觸控筆,還包括Wacom繪圖板之類的設備。在將來,可以方便地囊括體感電視遙 控器、Kinect動作。這兩種操作都可以操控指針、激活元素,比如激活鏈接。(不過,關冰箱門事件不在這個范圍內。)所以,指針事件比相互分離的鼠標和 觸摸事件有更好的前景。
我們來試試在上面三個實例中實現指針事件。
-
拖放操作完美匹配:無論用戶是用鼠標還是觸摸,亦或是觸控筆選中了一個元素,拖動它然后放下它。指針事件都可以在不增加代碼的情況下支持Kinect、電視遙控和其他類似指針的操作。
-
滾動層可以在指針事件下正常工作。在觸摸交互模式下,滾動層完美工作。當使用觸控筆時,用戶在滾動層按下、滾動,最后釋放。這個操作也講得 通。鼠標操作和觸控筆相似,但是按下筆選取滾動層這個操作有些奇怪。這也是為什么我覺得對滾動層的操作很難移植到鼠標操作。不過,無論我們使用分離的鼠 標、觸摸事件還是使用指針事件,這個問題仍然存在。所以指針事件不會帶來額外的問題。
-
下拉菜單是三個實例中最復雜的一個。pointerover和pointerout看似恰是為下拉菜單設計的。但是仔細一看,完全不是。下拉菜單無法很好地在觸摸交互下工作,就算換成指針事件也一樣。最好的處理方法還是用點擊(click)事件。
上面的實例說明,當某種交互不是專門針對某個操作模式設計的時候,指針事件就能很好地工作。在后面我 們會討論,如果你愿意,你還是可以通過指針事件對象的pointerType屬性來判斷是鼠標還是觸摸操作。(指針事件的初衷是統一鼠標、觸摸事件,顯然 這個屬性與初衷相悖,不過這也是實踐所需。)
mouseover和pointerover
pointerover融合了mouseover事件和我們虛構的“touchover”事件:在鼠 標指針或用戶手指滑入某個元素時觸發。pointerout則是在用戶手指或鼠標指針離開某個元素時觸發。這就是我們在CSS章節討論的:hover問 題,只不過是在JavaScript上下文中。
我們再一次遇到了連續事件和非連續事件的本質區別。當使用鼠標從A移動到B時,用戶必須經過A、B之 間的元素,別無選擇。但是觸摸操作就可以先觸摸A,再直接觸摸B,中間不會碰到其他任何元素。除非是在拖放元素,手指不能離開屏幕。此時 pointerover就很有用了:可以在pointerover時判斷當前滑入的對象是不是一個合法的放置區域。
除了這種情景,pointerover與mouseover還是有本質區別的。尤其是在鼠標移入某個 區域后顯示額外信息這類精細的操作中,鼠標移入(mouseover)根本無法正常工作。因為此時用戶的觸摸操作不太可能從某個地方移入期望的區域。更可 能的情況是,用戶直接觸摸相應的元素,而沒有任何移入(pointerover)操作。當然,額外的信息也就無法展現出來了。
解決辦法是,只處理mouseover和mouseout事件。因為這兩個事件在觸摸操作時都會被觸發。僅在觸摸點移入和移出時不會觸發,這一點我們在后面會詳細解釋。雖然有了這個解決方案,但是由于懸停操作在觸摸環境下實在是太另類了,所以這個方案并不完美。
輸入模式的漸進增強
漸進增強就像響應式設計教導我們的,要支持各種屏幕尺寸的設備,我們必須想辦法來支持多種輸入模式(這里的輸入模式指鼠標、觸摸、鍵盤等輸入模式)。我們暫且稱之為輸入模式的漸進增強。不過“輸入模式的漸進增強”的概念并沒有“響應式設計”那么一目了然。
“響應式設計”的基本思想是以同一個設計適應多種屏幕尺寸。而“輸入模式的漸進增強”在很多情況下需要我們為不同輸入模式分別編寫不同的腳本。比如前面講到的滾動層實例就需要我們為鼠標、鍵盤和觸摸寫三個不同的腳本。
除此之外,在用戶與網站交互的過程中,屏幕尺寸通常是不會改變的。而輸入模式卻可以頻繁改變。以微軟的Surface平板為例:在瀏覽同一頁面時,用戶可以在鼠標和觸摸操作之間隨意切換。而你的腳本必須支持這種復雜的操作。
通常情況下,相比智能手機來說,這種支持對平板電腦來說更重要。因為手機上的輸入模式相對少一些。盡管如此,也不要一廂情愿地假設在瀏覽頁面時用戶只使用一種輸入模式。雖然這種假設可以讓Web開發者的工作變得輕松一些,但是并不能改變這骨感的現實。
我們可以從響應式設計中借鑒一些思想應用到“輸入模式的漸進增強”中。在“響應式設計”中有一個好的 思想:從限制最多的情況著手,比如最小的屏幕。類似的,D-pad可以算是最局限的輸入模式了。它由四個方向鍵和一個OK鍵組成。好消息是,D-pad的 按鍵完全和普通鍵盤兼容:觸發相同的事件、使用相同的鍵碼。所以我們不需要區分D-pad和普通鍵盤。壞消息是,盡管如此,它們還是很有局限性。更壞的消 息是,在這方面我也沒有什么指導意見可以分享。因為“輸入模式的漸進增強”這個概念太新了,以至于我們還沒有找到普適的應對策略。而且連一些可以幫助大家 的好點子都很少。你可以把這視為一個問題,也可以視為一個挑戰。誰知道呢,沒準你就是那個教會這個世界如何實現“輸入模式的漸進增強”的人。
判斷當前的交互模式
“輸入模式的漸進增強”可能需要你去檢測用戶的當前交互模式。盡管很困難,但這在技術上可以實現。然而,我們真正的問題是,它究竟能提供哪些有用的信息呢?
讓我們再次以微軟Surface的用戶為例。你可以檢測到用戶正在使用鼠標。但這是否意味著他們將在 整個會話中一直使用鼠標呢?不盡其然。事實上,他們很有可能、或者至少是偶爾地會使用鍵盤或是觸摸屏,又或者干脆把鍵盤和鼠標觸控板折疊起來,只使用觸摸 屏。假如發生了以上任一情況,那么你的互動模式檢測的價值何在呢?
你唯一可以確定的合理判斷是,當用戶以某種模式開始某個動作時,他們不會在中途切換模式。因此,如果 你檢測到用戶正移動鼠標進行拖放,那么他們不太可能在拖曳過程中切換到觸摸操作。但是,一旦拖放完成,用戶就可能選擇切換到觸摸、或繼續使用鼠標、亦或使 用鍵盤,來進行下一步操作。
你必須確保所有交互在任何交互模式下均可實現,這一點至關重要。鼠標、觸摸甚至鍵盤都應該可以執行拖放操作。一旦做到了這一點,那么用戶正在使用何種交互模式都將無關緊要。
讓我們假設,你有很好的理由去尋找當前的交互模式。也許你想收集一些數據來研究用戶的模式使用偏好。那么我們來看一下幾種可能性。
-
指針事件最簡單明了:它具備pointerType屬性,其值可以是mouse、touch或pen。找到當前值即可知道用戶的操作。另一 個簡單的情況:當有任何按鍵事件觸發時,用戶一定會使用鍵盤。但這與未來的交互無關——用戶仍然可能隨時轉換到鍵盤或是觸摸。但無論如何,這還是提供了一 些有用的信息。
-
與之類似的,當一個觸摸事件觸發時,你可以肯定你的用戶在當下一定正在使用觸摸交互模式。同理,這并不影響未來的交互,但至少提供了一些信息。
-
對于鼠標事件要格外小心:當用戶觸摸屏幕時,鼠標事件也會觸發,因此檢測交互模式并不適用于鼠標事件。檢測鼠標使用的方法就是排除其他交互模式。如果用戶沒有使用觸摸或鍵盤,那么他有可能正在使用鼠標。
目前有很多方法可以檢測到一個觸摸交互模式是否可用。其中有一種由Modernizr普及,但可惜并不十分可靠的方法是:
var hasTouch = !!('ontouchstart' in window);
“如果window對象有ontouchstart屬性,說明瀏覽器支持觸摸事件,我們就可以放心地 使用。”這可能正是你所想的。前半句的結論是“雖然正確”,但是,支持觸摸事件的瀏覽器并不一定運行在具有觸摸屏的設備上。比如,黑莓6的瀏覽器支持觸摸 事件,但它卻運行在一個非觸摸設備上。老版本的Chrome瀏覽器也有類似的問題。并且,依賴ontouchstart的方法讓IE變得無能為力。
唯一安全的檢測瀏覽器支持觸摸事件、運行在觸摸設備上并且用戶正在使用觸摸交互的方法就是看是否確實有觸摸或指針事件被觸發。
var hasTouch = false; document.ontouchstart = function () { hasTouch = true; } document.onpointerdown = function (e) { if (e.pointerType === 'touch') { hasTouch = true; } }
最好的辦法是依次檢測各種交互模式:首先從指針事件開始。pointerType屬性可以提供有用的信息。然后檢測觸摸事件。后面我們會看到觸摸操作還會觸發鼠標事件,所以只有當觸摸事件沒有觸發時,才考慮鼠標事件。最后輪到鍵盤。
var interactionMode; document.onpointerdown = function (e) { interactionMode = e.pointerType; } document.ontouchstart = function () { if (!interactionMode) { interactionMode = 'touch'; } } document.onmousedown = function () { if (!interactionMode) { interactionMode = 'mouse'; } } document.onkeydown = function () { if (!interactionMode) { interactionMode = 'keyboard'; } }
登錄界面或類似的地方是運行上面代碼的理想場景。在這個場景中,用戶必須與網站交互。當用戶登錄時, 用類似上面的代碼檢測用戶正在使用哪種交互方式。要注意,這也只能說明用戶在登錄時使用的交互模式,并不是整個交互過程都會使用這個模式。雖然信息有限, 但這段代碼還是有一定預測功能的。
盡管上面的方法無法預測用戶接下來會使用哪種交互模式,但是目前最好的處理不同交互模式的方法還是為鼠標、鍵盤和觸摸編寫不同的代碼。
書籍簡介
《移動Web手冊》主要講解了移動Web開發和傳統PC網站開發的不同之處。作者首先對移動互聯網相關的運營商、設備、操作系統和軟件進行了簡單的介紹,讓讀者理解移動開發的復雜之處。接下來對移動設備上的各種瀏覽器進行了詳細介紹,以及這些瀏覽器的市場占有率、特性支持等。《移動Web手冊》為那些想進入移動Web開發領域的人提供了一些指導性的建議并對移動Web開發的未來進行了展望。
《移動Web手冊》主要面向前端開發工程師,對移動Web開發感興趣的手機App開發工程師以及測試工程師也可以參考學習。
作者簡介
Peter-Paul Koch(另一個更廣為人知的名字是PPK),是HTML、CSS和JavaScript方面的專家,尤其擅長解決瀏覽器兼容性問題。在2009年,他就從傳統的桌面瀏覽器和網站轉而研究移動Web領域,并且從未間斷。
來自:http://www.infoq.com/cn/articles/touch-pointer-event