不管在移動端還是PC端,我們都需要處理用戶點擊,這個最常用的事件。但在touch端click事件響應速度會比較慢,在較老的手機設備上會更為明顯(300ms的延遲)。
問題由來
這要追溯至 2007 年初。蘋果公司在發布首款 iPhone 前夕,遇到一個問題:當時的網站都是為大屏幕設備所設計的。於是蘋果的工程師們做了一些約定,應對 iPhone 這種小屏幕瀏覽桌面端站點的問題。
這當中最出名的,當屬雙擊縮放(double tap to zoom),這也是會有上述 300 毫秒延遲的主要原因。雙擊縮放,顧名思義,即用手指在屏幕上快速點擊兩次,iOS 自帶的 Safari 瀏覽器會將網頁縮放至原始比例。
那么這和 300 毫秒延遲有什么聯系呢?
假定這么一個場景。用戶在 iOS Safari 里邊點擊了一個鏈接。由於用戶可以進行雙擊縮放或者雙擊滾動的操作,當用戶一次點擊屏幕之后,瀏覽器並不能立刻判斷用戶是確實要打開這個鏈接,還是想要進行雙擊操作。因此,iOS Safari 就等待 300 毫秒,以判斷用戶是否再次點擊了屏幕。
鑒於iPhone的成功,其他移動瀏覽器都復制了 iPhone Safari 瀏覽器的多數約定,包括雙擊縮放,幾乎現在所有的移動端瀏覽器都有這個功能。之前人們剛剛接觸移動端的頁面,在欣喜的時候往往不會care這個300ms的延時問題,可是如今touch端界面如雨后春筍,用戶對體驗的要求也更高,這300ms帶來的卡頓慢慢變得讓人難以接受。
那么我們該如何解決這個問題,可能有的同學會想到touchstart事件,這個事件響應速度很快啊,如果說開發的界面上面可點擊的地方很少,要么用戶滑動下手指就觸發touchstart事件,也會讓人崩潰的。大家可以參考如下的幾種方法。
粗暴型:禁用縮放
<meta name="viewport" content="width=device-width, user-scalable=no">
關鍵是 user-scalable = no。
這個屬於簡單粗暴型的,雖然看似完美,但有一個致命的缺陷,當你必須完全禁用縮放來達到目的時候,就傻眼了,只有特定場景下的交互界面,此方案才可行,其它大多數情況,此法都不可行。 另外:Chrome 開發團隊不久前宣布,在 Chrome 32 這一版中,他們將在包含 width=device-width 或者置為比 viewport 值更小的頁面上禁用雙擊縮放。當然,沒有雙擊縮放就沒有 300 毫秒點擊延遲。
指針事件 (Pointer Events)
指針事件最初由微軟提出,現已進入 W3C 規范的候選推薦標准階段 (Candidate Recommendation)。這個草案規范旨在使用一個單獨的事件模型,對所有輸入類型,包括鼠標 (mouse)、觸摸 (touch)、觸控 (stylus) 等,進行統一的處理。
比如用css設置-ms-touch-action: none,那么對應的元素在被點擊之后,瀏覽器不會啟動縮放操作,也就避免了這個300ms延遲,但目前只有IE10+支持,目前touch開發的重點在safari和chrome,因此你懂的,此方案目前兼容性不好,不過chrome表示會在未來版本中支持的。
指針事件 (使非IE也支持)
上面也說道touch-action: none是一個辦法,那么其它瀏覽器不支持怎么辦呢?下面的幾個類庫是關於這方面的,感興趣的可以去研究下:
1.Google的Polymer
2.微軟的 HandJS
3.@Rich-Harris 的 Points
touch-action: none這種方案雖然可以解決這個問題,但影響的面比較廣,不是單純的來解決300ms延時問題的,有可能會帶來性能和其它操作上的隱患,慎用。
FastClick:閃亮登場
FastClick是FT Labs專門為解決移動端瀏覽器 300 毫秒點擊延遲問題所開發的一個輕量級的庫。簡而言之,FastClick 在檢測到 touchend 事件的時候,會通過 DOM 自定義事件立即觸發一個模擬 click 事件,並把瀏覽器在 300 毫秒之后真正觸發的click事件阻止掉。
FastClick 的使用方法非常簡單,在 window load 事件之后,在body上調用FastClick.attach()即可。
window.addEventListener( "load", function() {
FastClick.attach( document.body );
}, false );
attach方法雖可在更具體的元素上調用,直接綁定到body上可以確保整個應用都能受益。當 FastClick 檢測到當前頁面使用meta設置了user-scalable=no或者 touch-action 屬性的解決方案時,會靜默退出。可以說,這是真正的跨平台方案出來之前一種很好的變通方案。
就目前而言,FastClick 非常實際地解決 300 毫秒點擊延遲的問題,唯一的缺點可能也就是該腳本的文件尺寸 (盡管它只有10kb)。如果你連這10kb都接受不了的話,那么移動端類庫 jQuery和zepto.js都支持tap事件來解決這個問題,盡管它們的響應速度比FastClick慢一些。
正是因為有這些解決方案,那么首先還是挑選眼前更合適的吧,畢竟以后會不會出新標准來解決這個問題,誰都不知道,理論上來說FastClick也是屬於替代方案,希望有一天touch 端的開發可以不走pc的路,讓本來都苦逼的前端雪上加霜。
