摘要:由于移動設備能夠同時識別和事件,因此當用戶點擊目標元素時,綁定在目標元素上的事件與事件約后會依次被觸發,也就是說,我們所綁定的回調函數會被執行兩次。
一 · 業務場景的描述
在對已完成的PC站點進行移動端適配時,我們想要站點在移動設備上有更快的響應速度,以帶給用戶更好的體驗,此時,我們應該使用移動設備專用的事件系統,例如,使用
touchstart 事件代替 click 事件。
為什么這樣效果會更好呢?根據Google開發者文檔中的描述:
mobile browsers will wait approximately 300ms from the time that you tap the button to fire the click event. The reason for this is that the browser is waiting to see if you are actually performing a double tap.
移動設備上的瀏覽器將會在 click 事件觸發時延遲 300ms ,以確保這是一個“單擊”事件而非“雙擊”事件。
而對于 touchstart 事件而言,則會在用戶手指觸碰屏幕的一瞬間觸發所綁定的事件。所以,使用 touchstart 替換 click 事件的意義在于,幫助用戶在每次點擊時節省 300ms 的時間。在頁面頻繁需要點擊,或者點擊發生在動畫中,對動畫流暢度有較高要求的情境下,使用這種技術是非常必要的。
但是,讓我們回到我們的初始場景,在 PC端站點適配移動端時 我們不能簡單的進行 touchstart 和 click 事件的替換,因為PC并不能識別 touchstart 事件。
二 · 產生沖突的原因當然,我們可以給某個元素同時綁定 touchstart 和 click 事件,但這將會導致本篇文章解決的問題 -- 這兩個事件在移動設備上會發生沖突。
由于移動設備能夠同時識別 touchstart 和 click 事件,因此當用戶點擊目標元素時,綁定在目標元素上的 touchstart 事件與 click 事件(約300ms后)會依次被觸發,也就是說,我們所綁定的回調函數會被執行兩次!。這顯然不是我們想要的結果。
三 · 解決方案針對這樣的情境,有以下兩種解決方案:
(一)使用 preventDefault第一種解決方案是使用事件對象中的 preventDefault 方法,對于該方法MDN上的解釋是:
The Event interface"s preventDefault() method tells the user agent that if the event does not get explicitly handled, its default action should not be taken as it normally would be.
可見, preventDefault 方法的作用在于:阻止元素默認事件行為的發生,但有意思的是,當我們在目標元素同時綁定 touchstart 和 click 事件時,在 touchstart 事件回調函數中使用該方法,可以阻止后續 click 事件的發生。
這從道理上是講不通的,畢竟,我們添加的 click 事件并不是元素的“默認事件”,但它確實奏效了,或者說,被瀏覽器實現了,因此我們可以使用該方法解決移動設備上 touchstart 事件與 click 事件的沖突問題,具體代碼如下:
const Button = document.getElementById("targetButton") Button.addEventListener("touchstart", e => { e.preventDefault() console.log("touchstart event!") }) Button.addEventListener("click", e => { e.preventDefault() console.log("click event!") })
當你在瀏覽器上模擬移動設備后點擊目標元素,只會在控制臺看到 touchstart event! 字段,很顯然,click 事件被成功阻止了。
總結
使用該方法的優點在于簡單粗暴,直接有效,能夠很好的實現我們的目標,但缺點在于, preventDefault 方法為阻止 click 事件的方式是瀏覽器實現上的,而不是 preventDefault 原理上的,這會帶來一些不確定性,雖然我暫時尚未發現該方法失效的具體場景。
(二)基于功能檢測綁定事件第二種方法是受到這篇博客的啟發,我們可以通過判斷瀏覽器是否支持 touchstart 事件來封裝元素的點擊事件,這樣客戶端會根據當前環境判定元素應該綁定的事件類型,代碼如下:
const Button = document.getElementById("targetButton") const clickEvent = (function() { if ("ontouchstart" in document.documentElement === true) return "touchstart"; else return "click"; })(); Button.addEventListener(clickEvent, e => { console.log("things happened!") })
總結
該方法的優點在于,我們通過增加一次判斷,為元素減少了一個不必要的事件綁定,從而避免了 touchstart 與 click 事件的沖突問題。這種方法避免了我們書寫兩次同樣的代碼,并且相較于第一種方法更加符合邏輯,因此是我所推薦的。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/92938.html
摘要:所以這種情況下是不符合點擊事件的定義的。,關于移動端的點擊事件總結完了,可能你都沒想到一個簡單的點擊事件會有那么多坑,如果你在工作中可能會涉及到移動端開發的話,相信這篇文章還是值得你點贊和收藏的,畢竟是踩了那么多坑的經驗總結。 看標題的時候你可能會想,點擊事件有什么好說的,還寫一篇攻略?哈哈,如果你這么想,只能說明你too young to simple. 接觸過移動端開發的同學可能都...
摘要:所以這種情況下是不符合點擊事件的定義的。,關于移動端的點擊事件總結完了,可能你都沒想到一個簡單的點擊事件會有那么多坑,如果你在工作中可能會涉及到移動端開發的話,相信這篇文章還是值得你點贊和收藏的,畢竟是踩了那么多坑的經驗總結。 看標題的時候你可能會想,點擊事件有什么好說的,還寫一篇攻略?哈哈,如果你這么想,只能說明你too young to simple. 接觸過移動端開發的同學可能都...
摘要:所以這種情況下是不符合點擊事件的定義的。,關于移動端的點擊事件總結完了,可能你都沒想到一個簡單的點擊事件會有那么多坑,如果你在工作中可能會涉及到移動端開發的話,相信這篇文章還是值得你點贊和收藏的,畢竟是踩了那么多坑的經驗總結。 看標題的時候你可能會想,點擊事件有什么好說的,還寫一篇攻略?哈哈,如果你這么想,只能說明你too young to simple. 接觸過移動端開發的同學可能都...
摘要:二分析排查一步驟一使用搜索引擎我是在無意中發現該問題的,當時觀察到的現象是綁定在上的事件有時會被觸發,有時會失效。這說明并不存在偶爾失效的問題。也就是說,我需要找到確切的令響應事件失效的原因。接下來的事很簡單,繼續搜索事件在頁面滾動后失效。 如果你關注我應該知道,我最近對PC端頁面進行移動適配。在這個過程中,為了節省用戶300ms的時間,同時給予用戶更及時的點擊反饋(這意味著更好的用戶...
閱讀 2772·2021-10-14 09:42
閱讀 827·2021-10-11 10:57
閱讀 773·2019-08-30 15:54
閱讀 1914·2019-08-30 13:50
閱讀 1686·2019-08-30 11:19
閱讀 932·2019-08-29 12:38
閱讀 1425·2019-08-26 11:51
閱讀 1388·2019-08-26 10:48