1、前言javascript
移動端瀏覽器提供一個特殊的功能:雙擊(double tap)縮放。css
2、移動端延遲300ms的緣由html
爲何要用觸摸事件?觸摸事件是移動端瀏覽器特有的html5事件。html5
由於移動端的click有很大延遲(大約300ms),300ms延遲來自判斷雙擊和長按,由於只有默認等待時間結束以肯定沒有後續動做發生時,纔會觸發click事件。而觸摸事件的延遲則是很是短的,使用觸摸事件的可以提升頁面響應速度,帶來更好的用戶體驗。java
重點:因爲移動端會有雙擊縮放的這個操做,所以瀏覽器在click以後要等待300ms,看用戶有沒有下一次點擊,也就是此次操做是否是雙擊。git
3、瀏覽器開發商的解決方案github
一、方案一:禁用縮放瀏覽器
當HTML文檔頭部包含以下meta
標籤時:函數
<meta name="viewport" content="user-scalable=no"> <meta name="viewport" content="initial-scale=1,maximum-scale=1">
代表這個頁面是不可縮放的,那雙擊縮放的功能就沒有意義了,此時瀏覽器能夠禁用默認的雙擊縮放行爲而且去掉300ms的點擊延遲。學習
缺點:就是必須經過徹底禁用縮放來達到去掉點擊延遲的目的,然而徹底禁用縮放並非咱們的初衷,咱們只是想禁掉默認的雙擊縮放行爲,這樣就不用等待300ms來判斷當前操做是不是雙擊。可是一般狀況下,咱們仍是但願頁面能經過雙指縮放來進行縮放操做,好比放大一張圖片,放大一段很小的文字。
二、方案二:更改默認的視口窗口
爲了讓桌面站點能在移動端瀏覽器正常顯示,移動端瀏覽器默認的視口寬度!=設備瀏覽器視窗寬度,而是視口寬度要比設備寬度大,一般是980px。
咱們能夠經過如下標籤來設置視口寬度爲設備寬度。
<meta name="viewport" content="width=device-width">
對移動端坐過適配和優化了,這個時候就不須要雙擊縮放了。若是可以識別出一個網站是響應式的網站,那麼移動端瀏覽器就能夠自動禁掉默認的雙擊縮放行爲而且去掉300ms的點擊延遲。若是設置了上述meta
標籤,那瀏覽器就能夠認爲該網站已經對移動端作過了適配和優化,就無需雙擊縮放操做了。
這個方案相比方案一的好處在於,它沒有徹底禁用縮放,而只是禁用了瀏覽器默認的雙擊縮放行爲,但用戶仍然能夠經過雙指縮放操做來縮放頁面。
除了IE以外的大部分瀏覽器都不支持這個新的CSS屬性。touch-action這個CSS屬性。這個屬性指定了相應元素上可以觸發的用戶代理(也就是瀏覽器)的默認行爲。若是將該屬性值設置爲touch-action: none,那麼表示在該元素上的操做不會觸發用戶代理的任何默認行爲,就無需進行300ms的延遲判斷。
4、代碼解決方案
一、方案一:指針事件polyfill
除了IE,其餘大部分瀏覽器都還不支持指針事件。有一些JS庫,可讓咱們提早使用指針事件。好比:
(1)谷歌的Polymer
(2)微軟的HandJS
(3)@Rich-Harris 的 Points
關心的不是指針事件,而是與300ms延遲相關的CSS屬性touch-action。因爲除了IE以外的大部分瀏覽器都不支持這個新的CSS屬性,因此這些指針事件的polyfill必須經過某種方式去模擬支持這個屬性。一種方案是JS去請求解析全部的樣式表,另外一種方案是將
touch-action
做爲html標籤的屬性。
二、方案二:FastClick
FastClick是FT Labs專門爲解決移動端瀏覽器 300 毫秒點擊延遲問題所開發的一個輕量級的庫。FastClick的實現原理是在檢測到touchend事件的時候,會經過DOM自定義事件當即出發模擬一個click事件,並把瀏覽器在300ms以後的click事件阻止掉。
5、點擊穿透問題
說完移動端點擊300ms延遲的問題,還不得不提一下移動端點擊穿透的問題。既然click點擊有300ms的延遲,那對於觸摸屏,咱們直接監聽touchstart事件不就行了嗎?
使用touchstart去代替click事件有兩個很差的地方。
第一:touchstart是手指觸摸屏幕就觸發,有時候用戶只是想滑動屏幕,卻觸發了touchstart事件,這不是咱們想要的結果;
第二:使用touchstart事件在某些場景下可能會出現點擊穿透的現象。
一、什麼是點擊穿透?
假如頁面上有兩個元素A和B。B元素在A元素之上。咱們在B元素的touchstart事件上註冊了一個回調函數,該回調函數的做用是隱藏B元素。咱們發現,當咱們點擊B元素,B元素被隱藏了,隨後,A元素觸發了click事件。
這是由於在移動端瀏覽器,事件執行的順序是touchstart > touchend > click。而click事件有300ms的延遲,當touchstart事件把B元素隱藏以後,隔了300ms,瀏覽器觸發了click事件,可是此時B元素不見了,因此該事件被派發到了A元素身上。若是A元素是一個連接,那此時頁面就會意外地跳轉。
二、點擊穿透現象3種狀況
(1)點擊穿透問題:點擊蒙層(mask)上的關閉按鈕,蒙層消失後發現觸發了按鈕下面元素的click事件。
(2)跨頁面點擊穿透問題:若是按鈕下面剛好是一個有href屬性的a標籤,那麼頁面就會發生跳轉由於 a標籤跳轉默認是click事件觸發 ,因此原理和上面的徹底相同
(3)點擊穿透問題:此次沒有mask了,直接點擊頁內按鈕跳轉至新頁,而後發現新頁面中對應位置元素的click事件被觸發了。
三、解決方案
2種思路:
(1)不要混用touch和click。既然touch以後300ms會觸發click,只用touch或者只用click就天然不會存在問題了。
(2)用掉(或者說是消費掉)touch以後的click。依舊用tap,只是在可能發生點擊穿透的情形作額外的處理,拿個東西來擋住、或者tap後延遲350毫秒再隱藏mask、pointer-events、在下面元素的事件處理器裏作檢測(配合全局flag)
詳細方案:
(1)只用touch
最簡單的解決方案,完美解決點擊穿透問題。
把頁面內全部click所有換成touch事件 touchstart
、’touchend’、’tap’, 須要特別注意 a標籤,a標籤的href也是click,須要去掉換成js控制的跳轉,或者直接改爲span + tap控制跳轉。
(2)只用click
下下策 ,由於會帶來300ms延遲,頁面內任何一個自定義交互都將增長300毫秒延遲,想一想都慢。不用touch就不會存在touch以後300ms觸發click的問題。
(3)拿個東西擋住
比較笨的方法, 千萬不要用。更多信息請查看 【移動端兼容問題研究】javascript事件機制詳解(涉及移動兼容)
(4)tap後延遲350ms再隱藏mask
改動最小,缺點是隱藏mask變慢了,350ms仍是能感受到慢的。
(5)pointer-events
比較麻煩且有缺陷, 不建議使用。mask隱藏後,給按鈕下面元素添上 pointer-events: none; 樣式,讓click穿過去,350ms後去掉這個樣式,恢復響應。缺陷是mask消失後的的350ms內,用戶能夠看到按鈕下面的元素點着沒反應,若是用戶手速很快的話必定會發現。
(6)在下面元素的事件處理器裏作檢測(配合全局flag)
比較麻煩, 不建議使用。全局flag記錄按鈕點擊的位置(座標點),在下面元素的事件處理器裏判斷event的座標點,若是相同則是那個可惡的click,拒絕響應。
(7)fastclick
好用的解決方案,不介意多加載幾KB的話, 不建議使用 ,由於有人遇到了bug,更多信息請查看: Fastclick 致使click事件觸發兩次的問題。
首先引入fastclick庫,再把頁面內全部touch事件都換成click,其實稍微有點麻煩,建議引入這幾KB就爲了解決點透問題不值得,不如用第一種方法呢。
6、瀏覽器事件觸發的順序
touchstart --> mouseover(有的瀏覽器沒有實現) --> mousemove(一次) -->mousedown --> mouseup --> click -->touchend
Touch 事件中,經常使用的爲 touchstart, touchmove, touchend 三種。除此以外還有touchcancel。 注意,原生事件中並無tap事件。
事件描述以下:
事件 | 描述 | 觸發時機 |
---|---|---|
touchstart | 開始觸摸 | 手指接觸屏幕時當即觸發 |
touchmove | 移動或拖拽 | 取決於系統和瀏覽器 |
touchend | 觸摸結束 | 手指離開屏幕時當即出發 |
而Touch事件的觸發通常經過手指,還會存在多點觸控,拖拽方向等狀況。列出幾個重要參數以下:
參數 | 含義 |
---|---|
touches | 屏幕中每根手指信息列表 |
targetTouches | 和touches相似,把同一節點的手指信息過濾掉 |
changedTouches | 響應當前事件的每根手指的信息列表 |
代碼獲取以下:
elemenrRef.addEventListener('touchstart', function(e) { console.log(e.touches, e.targetTouches, e.changedTouches);} );
手指觸發觸摸事件的過程以下:
touchstart --> mouseover(有的瀏覽器沒有實現) --> mousemove(一次) -->mousedown --> mouseup --> click -->touchend
由此,咱們能夠在 ontouchstart 事件上記錄開始觸摸開始,ontouchend 記錄觸摸結束信息。 經過上述這些參數,很容易的去計算幽冥點擊的時間,以及點擊穿透的相關信息,包括響應的座標狀況。
【注:我是saucxs,也叫songEagle,鬆寶寫代碼,文章首發於sau交流學習社區 https://www.mwcxs.top),關注咱們天天閱讀更多精彩內容】
原文出處:https://www.cnblogs.com/chengxs/p/11064469.html