fastclick 解决移动端click事件300ms延迟
移動(dòng)端click 事件延遲300ms
一般情況下,如果沒有經(jīng)過(guò)特殊處理,移動(dòng)端瀏覽器在派發(fā)點(diǎn)擊事件的時(shí)候,通常會(huì)出現(xiàn)300ms左右的延遲。也就是說(shuō),當(dāng)我們點(diǎn)擊頁(yè)面的時(shí)候移動(dòng)端瀏覽器并不是立即作出反應(yīng),而是會(huì)等上一小會(huì)兒才會(huì)出現(xiàn)點(diǎn)擊的效果。在移動(dòng)WEB興起的初期,用戶對(duì)300ms的延遲感覺不明顯。但是,隨著用戶對(duì)交互體驗(yàn)的要求越來(lái)越高,現(xiàn)今,移動(dòng)端300ms的點(diǎn)擊延遲逐漸變得明顯而無(wú)法忍受。
那么,移動(dòng)端300ms的點(diǎn)擊延遲是怎么來(lái)的呢?
產(chǎn)生原因
移動(dòng)瀏覽器上支持的雙擊縮放操作,以及IOS Safari 上的雙擊滾動(dòng)操作,是導(dǎo)致300ms的點(diǎn)擊延遲主要原因。
預(yù)備知識(shí):移動(dòng)端點(diǎn)擊一個(gè)元素觸發(fā)事件的順序
以下是四種touch和click事件
touchstart: //手指放到屏幕上時(shí)觸發(fā)
touchmove: //手指在屏幕上滑動(dòng)式觸發(fā)
touchend: //手指離開屏幕時(shí)觸發(fā)
touchcancel: //系統(tǒng)取消touch事件的時(shí)候觸發(fā),這個(gè)好像比較少用
click://在這個(gè)dom(或冒泡到這個(gè)dom)上手指觸摸開始,且手指未曾在屏幕上移動(dòng)(某些瀏覽器允許移動(dòng)一個(gè)非常小的位移值),且在這個(gè)在這個(gè)dom上手指離開屏幕,且觸摸和離開屏幕之間的間隔時(shí)間較短(某些瀏覽器不檢測(cè)間隔時(shí)間,也會(huì)觸發(fā)click)才能觸發(fā)
上述事件發(fā)生順序:在移動(dòng)端,手指點(diǎn)擊一個(gè)元素,會(huì)經(jīng)過(guò):touchstart --> touchmove -> touchend --》click。
雙擊縮放:顧名思義,即用手指在屏幕上快速點(diǎn)擊兩次,移動(dòng)端瀏覽器會(huì)將網(wǎng)頁(yè)縮放至原始比例。 那么這和 300 毫秒延遲有什么聯(lián)系呢? 假定這么一個(gè)場(chǎng)景。用戶在 瀏覽器里邊點(diǎn)擊了一個(gè)鏈接。由于用戶可以進(jìn)行雙擊縮放或者雙擊滾動(dòng)的操作,當(dāng)用戶一次點(diǎn)擊屏幕之后,瀏覽器并不能立刻判斷用戶是確實(shí)要打開這個(gè)鏈接,還是想要進(jìn)行雙擊操作。因此,瀏覽器就等待 300 毫秒,以判斷用戶是否再次點(diǎn)擊了屏幕。
也就是說(shuō),移動(dòng)端瀏覽器會(huì)有一些默認(rèn)的行為,比如雙擊縮放、雙擊滾動(dòng)。這些行為,尤其是雙擊縮放,主要是為桌面網(wǎng)站在移動(dòng)端的瀏覽體驗(yàn)設(shè)計(jì)的。而在用戶對(duì)頁(yè)面進(jìn)行操作的時(shí)候,移動(dòng)端瀏覽器會(huì)優(yōu)先判斷用戶是否要觸發(fā)默認(rèn)的行為。
解決方案
禁用縮放
對(duì)于不需要縮放的頁(yè)面,通過(guò)設(shè)置meta標(biāo)簽禁用縮放,表明這個(gè)頁(yè)面是不需要縮放的,雙擊縮放就沒有意義了。此時(shí)瀏覽器可以禁用默認(rèn)的雙擊縮放行為并且去掉300ms的點(diǎn)擊延遲。
該方法缺點(diǎn)在于必須通過(guò)完全禁用縮放來(lái)達(dá)到去掉點(diǎn)擊延遲的目的,但我們初衷是想禁止默認(rèn)雙擊縮放行為,這樣就不用等待300ms來(lái)判斷當(dāng)前操作是否是雙擊。但是通常情況下我們還是希望能通過(guò)雙指縮放來(lái)進(jìn)行縮放操作,比如放大圖片,很小的一段文字。
更改默認(rèn)視口寬度
移動(dòng)端瀏覽器默認(rèn)視口寬度一般比設(shè)備瀏覽器視窗寬度大,通常是980px,我們可以通過(guò)如下標(biāo)簽設(shè)置視口寬度為設(shè)備寬度。
<pre><code><meta name="viewport" content="width=device-width"></code></pre>因?yàn)殡p擊縮放主要是用來(lái)改善桌面站點(diǎn)在移動(dòng)端瀏覽體驗(yàn)的,而隨著響應(yīng)式設(shè)計(jì)的普及,很多站點(diǎn)都已經(jīng)對(duì)移動(dòng)端坐過(guò)適配和優(yōu)化了,這個(gè)時(shí)候就不需要雙擊縮放了,如果能夠識(shí)別出一個(gè)網(wǎng)站是響應(yīng)式的網(wǎng)站,那么移動(dòng)端瀏覽器就可以自動(dòng)禁掉默認(rèn)的雙擊縮放行為并且去掉300ms的點(diǎn)擊延遲。chrome 32+中,如果設(shè)置了上述meta標(biāo)簽,那瀏覽器就可以認(rèn)為該網(wǎng)站已經(jīng)對(duì)移動(dòng)端做過(guò)了適配和優(yōu)化,就無(wú)需雙擊縮放操作了。
這個(gè)方案相比方案一的好處在于,它沒有完全禁用縮放,而只是禁用了瀏覽器默認(rèn)的雙擊縮放行為,但用戶仍然可以通過(guò)雙指縮放操作來(lái)縮放頁(yè)面。不足在于其他瀏覽器的支持有限。
css touch-action
指針事件(Point Event)最初由微軟提出,現(xiàn)已進(jìn)入 W3C 規(guī)范的候選推薦標(biāo)準(zhǔn)階段 (Candidate Recommendation)。指針事件是一個(gè)新的 web 事件系列,相應(yīng)的規(guī)范旨在使用一個(gè)單獨(dú)的事件模型,對(duì)所有輸入類型,包括鼠標(biāo) (mouse)、觸摸 (touch)、觸控 (stylus) 等,進(jìn)行統(tǒng)一的處理。
例如,你可以只去監(jiān)聽一個(gè)元素的 pointerdown事件,無(wú)需分別監(jiān)聽其 touchstart和mousedown事件。其中有一個(gè)和點(diǎn)擊延遲直接相關(guān)的實(shí)現(xiàn) —— 一個(gè)名為 touch-action的新 CSS 屬性。根據(jù)規(guī)范,touch-action
屬性決定 “是否觸摸操作會(huì)觸發(fā)用戶代理的默認(rèn)行為。這包括但不限于雙指縮放等行為”。
從實(shí)際應(yīng)用的角度來(lái)看,touch-action決定了用戶在點(diǎn)擊了目標(biāo)元素之后,是否能夠進(jìn)行雙指縮放或者雙擊縮放。因此,這也相當(dāng)完美地解決了 300 毫秒點(diǎn)擊延遲的問(wèn)題。touch-action的默為 auto,將其置為 none 即可移除目標(biāo)元素的 300 毫秒延遲。
目前而言,Internet Explorer 實(shí)現(xiàn)了指針事件,同時(shí),現(xiàn)在已經(jīng)有一些指針事件的 polyfills 可以在項(xiàng)目中使用了
指針事件的 polyfill
指針事件的 polyfill 比較多,以下列出比較流行的幾個(gè)。
Google 的 Polymer
微軟的 HandJS
@Rich-Harris 的 Points
為避免 300 毫秒點(diǎn)擊延遲,我們主要關(guān)心這些 polyfill 是如何在非 IE 瀏覽器中模擬 CSS touch-action屬性的,這其實(shí)是一個(gè)不小的挑戰(zhàn)。由于瀏覽器會(huì)忽略不被支持的 CSS 屬性,唯一能夠檢測(cè)開發(fā)者是否聲明了 touch-action: none的方法是使用 JavaScript 去請(qǐng)求并解析所有的樣式表。HandJS 也正是這么做的,但不管是從性能上來(lái)看還是其他一些復(fù)雜的方面,這都會(huì)遇到問(wèn)題。
Polymer 則是通過(guò)判斷標(biāo)簽上的 touch-action屬性 (attribute),而非 CSS 代碼。
這對(duì)于我們開發(fā)者來(lái)說(shuō)意味著什么?如果你比較感興趣,想深入指針事件,那上述 polyfill 就非常適合應(yīng)用到手頭的項(xiàng)目中。然而,你若只想尋求一個(gè)解決 300 毫秒點(diǎn)擊延遲的方法,上述方案可能就有點(diǎn)過(guò)了,因?yàn)樗鼈円词琴Y源密集型的方案,要么是touch-action屬性的非標(biāo)準(zhǔn)化模擬。所以,接下去我們要來(lái)看一些專門針對(duì) 300 毫秒延遲而生的解決方案
zepto等庫(kù)的 tap事件
zepto 的touch模塊中自定義了tap事件,用于代替click事件,表示一個(gè)輕擊操作。touch模塊實(shí)現(xiàn)tap的原理是綁定事件touchstart,touchmove和touchend到document上,然后通過(guò)計(jì)算touch事件觸發(fā)的時(shí)間差,位置差來(lái)實(shí)現(xiàn)了自定義的tap,swipe等。
zepto自定義的tap操作雖然可以解決300ms點(diǎn)擊延遲問(wèn)題,但存在著名的“點(diǎn)透”問(wèn)題。不知其最新版本有沒有解決該問(wèn)題。
fastclick 解決300ms延遲。
***** FastClick 是 FT Labs 專門為解決移動(dòng)端瀏覽器 300 毫秒點(diǎn)擊延遲問(wèn)題所開發(fā)的一個(gè)輕量級(jí)的庫(kù)。
基本原理:FastClick的實(shí)現(xiàn)原理是在檢測(cè)到touchend事件的時(shí)候,會(huì)通過(guò)DOM自定義事件立即出發(fā)模擬一個(gè)click事件,并把瀏覽器在300ms之后真正的click事件阻止掉。
fastClick的核心代碼
這里可以看到,FastClick在touchEnd的時(shí)候,在符合條件的情況下,主動(dòng)觸發(fā)了click事件,這樣避免了瀏覽器默認(rèn)的300毫秒等待判斷。為了防止原生的click被觸發(fā),這里還通過(guò)event.preventDefault()屏蔽了原生的click事件。
通過(guò)sendClick模擬click事件:
FastClick.prototype.sendClick = function(targetElement, event) { // 這里是一些狀態(tài)檢查邏輯 // 創(chuàng)建一個(gè)鼠標(biāo)事件 clickEvent = document.createEvent('MouseEvents'); // 初始化鼠標(biāo)事件為click事件 clickEvent.initMouseEvent(this.determineEventType(targetElement), true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null); // fastclick的內(nèi)部變量,用來(lái)識(shí)別click事件是原生還是模擬 clickEvent.forwardedTouchEvent = true; // 在目標(biāo)元素上觸發(fā)該鼠標(biāo)事件, targetElement.dispatchEvent(clickEvent);就目前而言,FastClick 非常實(shí)際地解決 300 毫秒點(diǎn)擊延遲的問(wèn)題。唯一的缺點(diǎn)可能也就是該腳本的文件尺寸 (盡管它只有 10kb)。
對(duì)比總結(jié)
禁用縮放:簡(jiǎn)單,但同時(shí)也使的網(wǎng)頁(yè)無(wú)法縮放,不適用于未對(duì)移動(dòng)端瀏覽做適配優(yōu)化的網(wǎng)頁(yè)。
更改默認(rèn)視口寬度:簡(jiǎn)單,但需要瀏覽器支持。
指針事件和css touch-action:新屬性,可能存在瀏覽器兼容問(wèn)題,如僅為解決點(diǎn)擊延遲問(wèn)題兒引入一整套指針事件有點(diǎn)過(guò)了。
tap事件:能較好解決點(diǎn)擊延遲,并且對(duì)其他移動(dòng)端觸摸事件也有較好支持,但存在點(diǎn)透問(wèn)題,不知最新版是否解決。
fastclick:當(dāng)前較好的專門解決點(diǎn)擊延遲的庫(kù),腳本尺寸相對(duì)較大。
作者:liusihowe
鏈接:https://www.jianshu.com/p/16d3e4f9b2a9
來(lái)源:簡(jiǎn)書
簡(jiǎn)書著作權(quán)歸作者所有,任何形式的轉(zhuǎn)載都請(qǐng)聯(lián)系作者獲得授權(quán)并注明出處。
總結(jié)
以上是生活随笔為你收集整理的fastclick 解决移动端click事件300ms延迟的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: SQL2014数据导入到SQL2008R
- 下一篇: 计算机音乐制作专业艺考,西安音乐学院20