一、背景 博主所負責其中一個項目是web頁面,在移動端上出現了事件穿透問題,開發介紹問題原因後,發覺是移動web一個知識點,值得記錄一下。 二、click與300ms延遲 移動瀏覽器提供一個特殊的功能:雙擊(double tap)放大 300ms的延遲就來自這裡,用戶觸碰頁面之後,需要等待一段時間來 ...
一、背景
博主所負責其中一個項目是web頁面,在移動端上出現了事件穿透問題,開發介紹問題原因後,發覺是移動web一個知識點,值得記錄一下。
二、click與300ms延遲
移動瀏覽器提供一個特殊的功能:雙擊(double tap)放大
300ms的延遲就來自這裡,用戶觸碰頁面之後,需要等待一段時間來判斷是不是雙擊(double tap)動作,而不是立即響應click(單擊),等待的這段時間大約是300ms。
- 移動端touch事件提供:
touchstart
、touchmove
、touchend
,卻沒有tap支持; - 主流框架/庫都是手動實現了tap事件,以求消除300ms延遲,提高頁面響應速度
- 對於簡單的頁面,可以把
touchstart
或者touchend
當作tap來用,但存在一些問題,比如手指接觸目標元素,按住不放,慢慢移出響應區域,會觸發touchstart
事件執行對應的事件處理器(本不應該觸發),touchend
事件也存在類似的問題。 - 使用原生的
touch
事件存在點擊穿透的問題,因為click是在touch系列事件發生後大約300ms才觸發,混用touch
和click
肯定會導致事件穿透。 - 手機上響應
click
事件有300ms的延遲,會有響應慢/延遲的感覺,因此很多移動頁面會使用touch/tap事件。
三、tap事件
用過Zepto
或者KISSY
等移動端js庫的人肯定對tap
事件不陌生,我們做PC頁面時候綁定click
,相應地手機頁面就綁定tap
。但原生的touch事件本身是沒有tap的,js庫提供的tap事件都是模擬出來的。
Zepto
中對tap事件處理:如果在touched響應250ms無操作後,則觸發singleTap。即事件觸發順序為:touch-tap-click。
三、點擊穿透問題
點擊穿透現象有3種:
- 點擊穿透問題:點擊蒙層(mask)上的關閉按鈕,蒙層消失後發現觸發了按鈕下麵元素的click事件。
- 解析:蒙層的關閉按鈕綁定的是touch事件,而按鈕下麵元素綁定的是click事件。touch事件觸發之後,蒙層消失了,300ms後這個點擊的click事件fire,event的target自然就是按鈕下麵的元素。
- 跨頁面點擊穿透問題:如果按鈕下麵恰好是有href屬性的a標簽,那麼頁面就會發生調整。因為
a標簽跳轉預設是click事件觸發
。原因同上。 - 第三種:這次沒有mask,直接點擊頁面內按鈕跳轉至新頁,然後發現新頁面中對應位置元素的click事件被觸發了。
- 解析:和蒙層的道理一樣,js控制頁面跳轉的邏輯如果是綁定在touch事件上的,而且新頁面中對應位置的元素綁定的是click事件,而且頁面在300ms內完成了跳轉,三個條件同時滿足,就出現這種情況。
四、解決方案
思路:
不要混用touch和click:touch之後300ms會觸發click,只有touch或者只用click就自然不會存在問題。
吃掉/消費掉touch之後的click
依舊使用tap,只是在可能發生點擊穿透的情形下做額外的處理,拿個東西來擋住、或者tap後延遲350ms再隱藏mask、pointer-events、在下麵元素的事件處理器里做檢測。
我們對事件響應速度要求不高,最後是通過延遲隱藏/關閉mask/彈窗解決的,簡單可控哈。
參考:https://juejin.im/entry/56ce9c97c24aa80052101aab