fastclick 解決移動(dòng)端click事件300ms延遲

liusihao 2016-12-21

移動(dòng)端click 事件延遲300ms


一般情況下,如果沒有經(jīng)過特殊處理,移動(dòng)端瀏覽器在派發(fā)點(diǎn)擊事件的時(shí)候,通常會(huì)出現(xiàn)300ms左右的延遲。也就是說,當(dāng)我們點(diǎn)擊頁面的時(shí)候移動(dòng)端瀏覽器并不是立即作出反應(yīng),而是會(huì)等上一小會(huì)兒才會(huì)出現(xiàn)點(diǎn)擊的效果。在移動(dòng)WEB興起的初期,用戶對(duì)300ms的延遲感覺不明顯。但是,隨著用戶對(duì)交互體驗(yàn)的要求越來越高,現(xiàn)今,移動(dòng)端300ms的點(diǎn)擊延遲逐漸變得明顯而無法忍受。

那么,移動(dòng)端300ms的點(diǎn)擊延遲是怎么來的呢?

產(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)過:touchstart --> touchmove -> touchend --》click。

雙擊縮放:顧名思義,即用手指在屏幕上快速點(diǎn)擊兩次,移動(dòng)端瀏覽器會(huì)將網(wǎng)頁縮放至原始比例。 那么這和 300 毫秒延遲有什么聯(lián)系呢? 假定這么一個(gè)場(chǎng)景。用戶在 瀏覽器里邊點(diǎn)擊了一個(gè)鏈接。由于用戶可以進(jìn)行雙擊縮放或者雙擊滾動(dòng)的操作,當(dāng)用戶一次點(diǎn)擊屏幕之后,瀏覽器并不能立刻判斷用戶是確實(shí)要打開這個(gè)鏈接,還是想要進(jìn)行雙擊操作。因此,瀏覽器就等待 300 毫秒,以判斷用戶是否再次點(diǎn)擊了屏幕。
也就是說,移動(dòng)端瀏覽器會(huì)有一些默認(rèn)的行為,比如雙擊縮放、雙擊滾動(dòng)。這些行為,尤其是雙擊縮放,主要是為桌面網(wǎng)站在移動(dòng)端的瀏覽體驗(yàn)設(shè)計(jì)的。而在用戶對(duì)頁面進(jìn)行操作的時(shí)候,移動(dòng)端瀏覽器會(huì)優(yōu)先判斷用戶是否要觸發(fā)默認(rèn)的行為。

解決方案

  • 禁用縮放

對(duì)于不需要縮放的頁面,通過設(shè)置meta標(biāo)簽禁用縮放,表明這個(gè)頁面是不需要縮放的,雙擊縮放就沒有意義了。此時(shí)瀏覽器可以禁用默認(rèn)的雙擊縮放行為并且去掉300ms的點(diǎn)擊延遲。
該方法缺點(diǎn)在于必須通過完全禁用縮放來達(dá)到去掉點(diǎn)擊延遲的目的,但我們初衷是想禁止默認(rèn)雙擊縮放行為,這樣就不用等待300ms來判斷當(dāng)前操作是否是雙擊。但是通常情況下我們還是希望能通過雙指縮放來進(jìn)行縮放操作,比如放大圖片,很小的一段文字。
<pre><code><meta name="viewport" content="user-scalable=no">
<meta name="viewport" content="initial-scale=1,maximum-scale=1"></code></pre>

  • 更改默認(rèn)視口寬度

移動(dòng)端瀏覽器默認(rèn)視口寬度一般比設(shè)備瀏覽器視窗寬度大,通常是980px,我們可以通過如下標(biāo)簽設(shè)置視口寬度為設(shè)備寬度。
<pre><code><meta name="viewport" content="width=device-width"></code></pre>
因?yàn)殡p擊縮放主要是用來改善桌面站點(diǎn)在移動(dòng)端瀏覽體驗(yàn)的,而隨著響應(yīng)式設(shè)計(jì)的普及,很多站點(diǎn)都已經(jīng)對(duì)移動(dòng)端坐過適配和優(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)端做過了適配和優(yōu)化,就無需雙擊縮放操作了。
這個(gè)方案相比方案一的好處在于,它沒有完全禁用縮放,而只是禁用了瀏覽器默認(rèn)的雙擊縮放行為,但用戶仍然可以通過雙指縮放操作來縮放頁面。不足在于其他瀏覽器的支持有限。

  • 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事件,無需分別監(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)用的角度來看,touch-action決定了用戶在點(diǎn)擊了目標(biāo)元素之后,是否能夠進(jìn)行雙指縮放或者雙擊縮放。因此,這也相當(dāng)完美地解決了 300 毫秒點(diǎ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-HarrisPoints
    為避免 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 也正是這么做的,但不管是從性能上來看還是其他一些復(fù)雜的方面,這都會(huì)遇到問題。
    Polymer 則是通過判斷標(biāo)簽上的 touch-action屬性 (attribute),而非 CSS 代碼。
    這對(duì)于我們開發(fā)者來說意味著什么?如果你比較感興趣,想深入指針事件,那上述 polyfill 就非常適合應(yīng)用到手頭的項(xiàng)目中。然而,你若只想尋求一個(gè)解決 300 毫秒點(diǎn)擊延遲的方法,上述方案可能就有點(diǎn)過了,因?yàn)樗鼈円词琴Y源密集型的方案,要么是touch-action屬性的非標(biāo)準(zhǔn)化模擬。所以,接下去我們要來看一些專門針對(duì) 300 毫秒延遲而生的解決方案

  • zepto等庫的 tap事件

zepto 的touch模塊中自定義了tap事件,用于代替click事件,表示一個(gè)輕擊操作。touch模塊實(shí)現(xiàn)tap的原理是綁定事件touchstart,touchmove和touchend到document上,然后通過計(jì)算touch事件觸發(fā)的時(shí)間差,位置差來實(shí)現(xiàn)了自定義的tap,swipe等。
zepto自定義的tap操作雖然可以解決300ms點(diǎn)擊延遲問題,但存在著名的“點(diǎn)透”問題。不知其最新版本有沒有解決該問題。

  • fastclick 解決300ms延遲。

***** FastClickFT Labs 專門為解決移動(dòng)端瀏覽器 300 毫秒點(diǎn)擊延遲問題所開發(fā)的一個(gè)輕量級(jí)的庫。

  • 基本原理:FastClick的實(shí)現(xiàn)原理是在檢測(cè)到touchend事件的時(shí)候,會(huì)通過DOM自定義事件立即出發(fā)模擬一個(gè)click事件,并把瀏覽器在300ms之后真正的click事件阻止掉。
  • fastClick的核心代碼
    <pre><code>FastClick.prototype.onTouchEnd = function(event){ // 一些狀態(tài)監(jiān)測(cè)代碼 // 從這里開始, if (!this.needsClick(targetElement)) { // 如果這不是一個(gè)需要使用原生click的元素,則屏蔽原生事件,避免觸發(fā)兩次click event.preventDefault(); // 觸發(fā)一次模擬的click this.sendClick(targetElement, event); }}</code></pre>
    這里可以看到,F(xiàn)astClick在touchEnd的時(shí)候,在符合條件的情況下,主動(dòng)觸發(fā)了click事件,這樣避免了瀏覽器默認(rèn)的300毫秒等待判斷。為了防止原生的click被觸發(fā),這里還通過event.preventDefault()屏蔽了原生的click事件。

通過sendClick模擬click事件:
<pre><code>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)部變量,用來識(shí)別click事件是原生還是模擬 clickEvent.forwardedTouchEvent = true; // 在目標(biāo)元素上觸發(fā)該鼠標(biāo)事件, targetElement.dispatchEvent(clickEvent);</code></pre>
就目前而言,F(xiàn)astClick 非常實(shí)際地解決 300 毫秒點(diǎn)擊延遲的問題。唯一的缺點(diǎn)可能也就是該腳本的文件尺寸 (盡管它只有 10kb)。

  • 對(duì)比總結(jié)

禁用縮放:簡(jiǎn)單,但同時(shí)也使的網(wǎng)頁無法縮放,不適用于未對(duì)移動(dòng)端瀏覽做適配優(yōu)化的網(wǎng)頁。
更改默認(rèn)視口寬度:簡(jiǎn)單,但需要瀏覽器支持。
指針事件和css touch-action:新屬性,可能存在瀏覽器兼容問題,如僅為解決點(diǎn)擊延遲問題兒引入一整套指針事件有點(diǎn)過了。
tap事件:能較好解決點(diǎn)擊延遲,并且對(duì)其他移動(dòng)端觸摸事件也有較好支持,但存在點(diǎn)透問題,不知最新版是否解決。
fastclick:當(dāng)前較好的專門解決點(diǎn)擊延遲的庫,腳本尺寸相對(duì)較大。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,702評(píng)論 6 534
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,615評(píng)論 3 419
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,606評(píng)論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,044評(píng)論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,826評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,227評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,307評(píng)論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,447評(píng)論 0 289
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,992評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,807評(píng)論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,001評(píng)論 1 370
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,550評(píng)論 5 361
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,243評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,667評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,930評(píng)論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,709評(píng)論 3 393
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,996評(píng)論 2 374

推薦閱讀更多精彩內(nèi)容