摘要:由于移動(dòng)設(shè)備能夠同時(shí)識(shí)別和事件,因此當(dāng)用戶點(diǎn)擊目標(biāo)元素時(shí),綁定在目標(biāo)元素上的事件與事件約后會(huì)依次被觸發(fā),也就是說(shuō),我們所綁定的回調(diào)函數(shù)會(huì)被執(zhí)行兩次。
一 · 業(yè)務(wù)場(chǎng)景的描述
在對(duì)已完成的PC站點(diǎn)進(jìn)行移動(dòng)端適配時(shí),我們想要站點(diǎn)在移動(dòng)設(shè)備上有更快的響應(yīng)速度,以帶給用戶更好的體驗(yàn),此時(shí),我們應(yīng)該使用移動(dòng)設(shè)備專用的事件系統(tǒng),例如,使用
touchstart 事件代替 click 事件。
為什么這樣效果會(huì)更好呢?根據(jù)Google開(kāi)發(fā)者文檔中的描述:
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.
移動(dòng)設(shè)備上的瀏覽器將會(huì)在 click 事件觸發(fā)時(shí)延遲 300ms ,以確保這是一個(gè)“單擊”事件而非“雙擊”事件。
而對(duì)于 touchstart 事件而言,則會(huì)在用戶手指觸碰屏幕的一瞬間觸發(fā)所綁定的事件。所以,使用 touchstart 替換 click 事件的意義在于,幫助用戶在每次點(diǎn)擊時(shí)節(jié)省 300ms 的時(shí)間。在頁(yè)面頻繁需要點(diǎn)擊,或者點(diǎn)擊發(fā)生在動(dòng)畫(huà)中,對(duì)動(dòng)畫(huà)流暢度有較高要求的情境下,使用這種技術(shù)是非常必要的。
但是,讓我們回到我們的初始場(chǎng)景,在 PC端站點(diǎn)適配移動(dòng)端時(shí) 我們不能簡(jiǎn)單的進(jìn)行 touchstart 和 click 事件的替換,因?yàn)镻C并不能識(shí)別 touchstart 事件。
二 · 產(chǎn)生沖突的原因當(dāng)然,我們可以給某個(gè)元素同時(shí)綁定 touchstart 和 click 事件,但這將會(huì)導(dǎo)致本篇文章解決的問(wèn)題 -- 這兩個(gè)事件在移動(dòng)設(shè)備上會(huì)發(fā)生沖突。
由于移動(dòng)設(shè)備能夠同時(shí)識(shí)別 touchstart 和 click 事件,因此當(dāng)用戶點(diǎn)擊目標(biāo)元素時(shí),綁定在目標(biāo)元素上的 touchstart 事件與 click 事件(約300ms后)會(huì)依次被觸發(fā),也就是說(shuō),我們所綁定的回調(diào)函數(shù)會(huì)被執(zhí)行兩次!。這顯然不是我們想要的結(jié)果。
三 · 解決方案針對(duì)這樣的情境,有以下兩種解決方案:
(一)使用 preventDefault第一種解決方案是使用事件對(duì)象中的 preventDefault 方法,對(duì)于該方法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.
可見(jiàn), preventDefault 方法的作用在于:阻止元素默認(rèn)事件行為的發(fā)生,但有意思的是,當(dāng)我們?cè)谀繕?biāo)元素同時(shí)綁定 touchstart 和 click 事件時(shí),在 touchstart 事件回調(diào)函數(shù)中使用該方法,可以阻止后續(xù) click 事件的發(fā)生。
這從道理上是講不通的,畢竟,我們添加的 click 事件并不是元素的“默認(rèn)事件”,但它確實(shí)奏效了,或者說(shuō),被瀏覽器實(shí)現(xiàn)了,因此我們可以使用該方法解決移動(dòng)設(shè)備上 touchstart 事件與 click 事件的沖突問(wèn)題,具體代碼如下:
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!") })
當(dāng)你在瀏覽器上模擬移動(dòng)設(shè)備后點(diǎn)擊目標(biāo)元素,只會(huì)在控制臺(tái)看到 touchstart event! 字段,很顯然,click 事件被成功阻止了。
總結(jié)
使用該方法的優(yōu)點(diǎn)在于簡(jiǎn)單粗暴,直接有效,能夠很好的實(shí)現(xiàn)我們的目標(biāo),但缺點(diǎn)在于, preventDefault 方法為阻止 click 事件的方式是瀏覽器實(shí)現(xiàn)上的,而不是 preventDefault 原理上的,這會(huì)帶來(lái)一些不確定性,雖然我暫時(shí)尚未發(fā)現(xiàn)該方法失效的具體場(chǎng)景。
(二)基于功能檢測(cè)綁定事件第二種方法是受到這篇博客的啟發(fā),我們可以通過(guò)判斷瀏覽器是否支持 touchstart 事件來(lái)封裝元素的點(diǎn)擊事件,這樣客戶端會(huì)根據(jù)當(dāng)前環(huán)境判定元素應(yīng)該綁定的事件類型,代碼如下:
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!") })
總結(jié)
該方法的優(yōu)點(diǎn)在于,我們通過(guò)增加一次判斷,為元素減少了一個(gè)不必要的事件綁定,從而避免了 touchstart 與 click 事件的沖突問(wèn)題。這種方法避免了我們書(shū)寫(xiě)兩次同樣的代碼,并且相較于第一種方法更加符合邏輯,因此是我所推薦的。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/92938.html
摘要:所以這種情況下是不符合點(diǎn)擊事件的定義的。,關(guān)于移動(dòng)端的點(diǎn)擊事件總結(jié)完了,可能你都沒(méi)想到一個(gè)簡(jiǎn)單的點(diǎn)擊事件會(huì)有那么多坑,如果你在工作中可能會(huì)涉及到移動(dòng)端開(kāi)發(fā)的話,相信這篇文章還是值得你點(diǎn)贊和收藏的,畢竟是踩了那么多坑的經(jīng)驗(yàn)總結(jié)。 看標(biāo)題的時(shí)候你可能會(huì)想,點(diǎn)擊事件有什么好說(shuō)的,還寫(xiě)一篇攻略?哈哈,如果你這么想,只能說(shuō)明你too young to simple. 接觸過(guò)移動(dòng)端開(kāi)發(fā)的同學(xué)可能都...
摘要:所以這種情況下是不符合點(diǎn)擊事件的定義的。,關(guān)于移動(dòng)端的點(diǎn)擊事件總結(jié)完了,可能你都沒(méi)想到一個(gè)簡(jiǎn)單的點(diǎn)擊事件會(huì)有那么多坑,如果你在工作中可能會(huì)涉及到移動(dòng)端開(kāi)發(fā)的話,相信這篇文章還是值得你點(diǎn)贊和收藏的,畢竟是踩了那么多坑的經(jīng)驗(yàn)總結(jié)。 看標(biāo)題的時(shí)候你可能會(huì)想,點(diǎn)擊事件有什么好說(shuō)的,還寫(xiě)一篇攻略?哈哈,如果你這么想,只能說(shuō)明你too young to simple. 接觸過(guò)移動(dòng)端開(kāi)發(fā)的同學(xué)可能都...
摘要:所以這種情況下是不符合點(diǎn)擊事件的定義的。,關(guān)于移動(dòng)端的點(diǎn)擊事件總結(jié)完了,可能你都沒(méi)想到一個(gè)簡(jiǎn)單的點(diǎn)擊事件會(huì)有那么多坑,如果你在工作中可能會(huì)涉及到移動(dòng)端開(kāi)發(fā)的話,相信這篇文章還是值得你點(diǎn)贊和收藏的,畢竟是踩了那么多坑的經(jīng)驗(yàn)總結(jié)。 看標(biāo)題的時(shí)候你可能會(huì)想,點(diǎn)擊事件有什么好說(shuō)的,還寫(xiě)一篇攻略?哈哈,如果你這么想,只能說(shuō)明你too young to simple. 接觸過(guò)移動(dòng)端開(kāi)發(fā)的同學(xué)可能都...
摘要:二分析排查一步驟一使用搜索引擎我是在無(wú)意中發(fā)現(xiàn)該問(wèn)題的,當(dāng)時(shí)觀察到的現(xiàn)象是綁定在上的事件有時(shí)會(huì)被觸發(fā),有時(shí)會(huì)失效。這說(shuō)明并不存在偶爾失效的問(wèn)題。也就是說(shuō),我需要找到確切的令響應(yīng)事件失效的原因。接下來(lái)的事很簡(jiǎn)單,繼續(xù)搜索事件在頁(yè)面滾動(dòng)后失效。 如果你關(guān)注我應(yīng)該知道,我最近對(duì)PC端頁(yè)面進(jìn)行移動(dòng)適配。在這個(gè)過(guò)程中,為了節(jié)省用戶300ms的時(shí)間,同時(shí)給予用戶更及時(shí)的點(diǎn)擊反饋(這意味著更好的用戶...
閱讀 2788·2021-10-14 09:42
閱讀 842·2021-10-11 10:57
閱讀 788·2019-08-30 15:54
閱讀 1931·2019-08-30 13:50
閱讀 1696·2019-08-30 11:19
閱讀 947·2019-08-29 12:38
閱讀 1439·2019-08-26 11:51
閱讀 1405·2019-08-26 10:48