摘要:所有瀏覽器瀏覽器不支持安卓中中有屬性安卓中中有屬性有屬性的有屬性的所以在不需要的瀏覽器會直接掉,不會執行下面的所有代碼。見源碼行,可以看出在響應無操作后,則觸發。
其實一直就想花些時間讀一讀那些優秀的開源庫,今天終于下了決定打算死磕下自己,2016年每個月讀2-3個優秀的開源庫,把源碼精彩的地方和自己心得分享給大家。
目錄(一)背景(一)背景
(二)源碼解析
(三)Zepto 點擊穿透與 FastClick
(四)新技能 Get
(五)參考文獻
做前端的一定都知道,原生click事件在移動瀏覽器上會有300毫秒的延遲,會讓用戶覺得卡頓,這300毫秒到底是怎么來的呢,估計就不太知道了,再繼續深究這300毫秒的來源是什么,應該會更少人知道吧。國外有一篇很有名的文章說的很詳細,有興趣可以看一下:what-exactly-is.....-the-300ms-click-delay。簡短來說:是移動瀏覽器都支持雙擊縮放或雙擊滾動的操作,由于當用戶第一次點擊屏幕后,瀏覽器不能立刻判斷用戶確實要打開這個鏈接,還是想要進行雙擊的操作,因此幾乎現在所有瀏覽器都效仿Safari當年的約定,在點擊事件上加了300毫秒的延遲。
在這個web頁面橫行的年代,每個點擊事件都有300毫秒的延遲是不允許的。再后來出來了很多的解決辦法,比如Zepto的tap事件(會引發擊穿的bug,后面會著重說),fastclick.js等都可以解決,但是多多少少會有些負作用,綜合起來我最喜歡fastclick的解決方案,今天就來讀一讀它的源碼吧~
(二)解析 1. 引入 FastClick 到自己的環境829行:現在一般插件都會用這種方式兼容AMD、commonJs風格、原生Js的方式。還有CMD等這里沒有兼容,這里可以根據自己項目需求稍作修改。
//優先兼容AMD方式 if (typeof define === "function" && typeof define.amd === "object" && define.amd) { define(function() { return FastClick; }); } else if (typeof module !== "undefined" && module.exports) { //兼容commonJs風格 module.exports = FastClick.attach; module.exports.FastClick = FastClick; } else { //最后兼容原生Js window.FastClick = FastClick; }2. 入口
824行:FastClick入口方法attach
//layer參數:要監聽的dom對象,一般是document.body //options參數:用來覆蓋自定義參數,個人建議不去覆蓋, //因為里面的參數設定都是FastClick的精華, //比如規定了touchstart和touchend事件之間的200毫秒最小間隔。 FastClick.attach = function(layer, options) { return new FastClick(layer, options); };3. FastClick 函數 1. 23-103行:設置默認值
//比如這幾個參數,上面提到不建議自定義覆蓋, //這些參數正是FastClick的精華所在, //大幅度修改數值可能讓整個庫的功效大打折扣。 this.touchBoundary = options.touchBoundary || 10; this.tapDelay = options.tapDelay || 200; this.tapTimeout = options.tapTimeout || 700;2. 105-107行:判斷是否需要調用FastClick
官網上when-it-isnt-needed說的很清楚,以下情況不需要FastClick。
所有pc瀏覽器
瀏覽器不支持ontouchstart
安卓中chrome(all versions)meta中有user-scalable="no"屬性
安卓中chrome 32+ meta中有width=device-width 屬性
BlackBerry 10.3+
Firefox 27+
有-ms-touch-action: manipulation屬性的IE10
有touch-action: manipulation屬性的IE11
//所以在不需要FastClick的瀏覽器會直接return掉, //不會執行下面的所有代碼。 if (FastClick.notNeeded(layer)) { return; }3. 110-132行:自定義函數綁定在對應默認事件上
layer.addEventListener("touchstart", this.onTouchStart, false); layer.addEventListener("touchmove", this.onTouchMove, false); layer.addEventListener("touchend", this.onTouchEnd, false); layer.addEventListener("touchcancel", this.onTouchCancel, false);4. 137-159行:對舊版本android不支持 stopImmediatePropagation 事件的兼容
這里有一個知識點:stopImmediatePropagation和stopPropagation的區別,后面總結會詳細說。
5. 164-173行:兼容直接綁定在dom上的onclick事件//把 直接綁定在dom上的onclick事件 //改為綁定在該dom上的形式, //為了之后的模擬點擊事件。 if (typeof layer.onclick === "function") { oldOnClick = layer.onclick; layer.addEventListener("click", function(event) { oldOnClick(event); }, false); layer.onclick = null; }4. 兼容 & 判斷
181-219行:瀏覽器UA判斷
311-319行:determineEventType 兼容安卓chrome中的select框事件從click改為mousedown
325-355行:focus 兼容蘋果手機setSelectionRange不能正確獲取焦點的bug
343-367行:updateScrollParent (待看)
374-382行:getTargetElementFromEventTarget 兼容獲取點擊元素,iOS 4.1中會獲取文字作為焦點,取它的父元素dom
497-512行:findControl
//點擊label的時候,找到他對應的元素,并獲取焦點
459-467:touchHasMoved 手指點擊時移動間距大于10px,返回true
476-488:onTouchMove 手指點擊時移動間距大于10px,即視為touchmove,不觸發模擬click事件
一般情況下用不到,以下方法,特殊需求可能會用到。
227-254行:needsClick 確定哪些元素需要原生的click事件
263-285行:needsFocus 確定哪些元素需要原生的focus事件
//如果哪些元素需要使用原生的click或者是focus事件,需要在dom上加上class="needsClick" Ignored by FastClick
712-726行:destroy 這個方法只在源碼中,如果有需求銷毀事件,重構源碼時可以調用這個方法。
6. 核心方法391-450:onTouchStart
FastClick.prototype.onTouchStart = function(event) { //tapDelay默認300毫秒,點擊時間差小于300毫秒,則阻止事件再次觸發,阻止短時間內雙擊的問題 if ((event.timeStamp - this.lastClickTime) < this.tapDelay) { event.preventDefault(); } }
521-610:onTouchEnd
if (!this.needsClick(targetElement)) { // 如果這不是一個需要使用原生click的元素,則屏蔽原生事件,避免觸發兩次click event.preventDefault(); // 觸發一次模擬的click this.sendClick(targetElement, event); }
294-309:sendClick(核心方法)
//這個事件會在onTouchEnd中用到,經過一系列的判斷,符合條件,調用這個模擬事件 FastClick.prototype.sendClick = function(targetElement, event) { var clickEvent, touch; //創建一個鼠標事件 clickEvent = document.createEvent("MouseEvents"); //初始化鼠標事件 clickEvent.initMouseEvent(this.determineEventType(targetElement), true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null); //觸發這個事件 targetElement.dispatchEvent(clickEvent); };(三)Zepto 點擊穿透與 FastClick
最近項目中在用Zepto的插件touch.js中tap事件,來解決移動瀏覽器中300毫秒延遲的問題。但是出現了各種擊穿現象
同頁面tap點擊彈出彈層,彈層中也有一個button,正好重疊的時候,會出現擊穿
tap事件點擊,頁面跳轉,新頁面中同位置也有一個按鈕,會出現擊穿
我們可以看下Zepto對 singleTap 事件的處理。見源碼 136-143 行,可以看出在 touchend 響應 250ms 無操作后,則觸發singleTap。
//trigger single tap after 250ms of inactivity else { touchTimeout = setTimeout(function(){ touchTimeout = null if (touch.el) touch.el.trigger("singleTap") touch = {} }, 250) }
用這篇文章里面的一句話來解釋下Zepto的穿透問題也來說說touch事件與點擊穿透問題
zepto中的 tap 通過兼聽綁定在 document 上的 touch 事件來完成 tap 事件的模擬的,是通過事件冒泡實現的。在點擊完成時(touchstart / touchend)的 tap 事件需要冒泡到 document 上才會觸發。而在冒泡到 document 之前,手指接觸和離開屏幕(touchstart / touchend)是會觸發 click 事件的。
因為 click 事件有延遲(大概是300ms,為了實現safari的雙擊事件的設計),所以在執行完 tap 事件之后,彈出層立馬就隱藏了,此時 click 事件還在延遲的 300ms 之中。當 300ms 到來的時候,click 到的其實是隱藏元素下方的元素。
如果正下方的元素有綁定 click 事件,此時便會觸發,如果沒有綁定 click 事件的話就當沒發生。如果正下方的是 input 輸入框(或是 select / radio / checkbox),點擊默認 focus 而彈出輸入鍵盤,也就出現了上面的“點透”現象。
所以到這里,個人還是建議直接使用fastclick.js庫來解決移動端瀏覽器300毫秒的問題,不建議自己寫,坑還是挺多的,這個庫壓縮后還是挺小的,可以用各種方式引用,來替代Zepto中的touch.js插件是個不錯的辦法。
(四)新技能 Get通過讀這個庫,發現了很多知識上的盲區或者理解的并不是很透徹的點,再深化一下~
stopImmediatePropagation 和 stopPropagation 的區別 參考文章
他們都可以阻止事件冒泡到父元素
stopImmediatePropagation多做了一件事:阻止綁定在該元素上其他事件運行
(五)參考文獻300毫秒的起源:what-exactly-is.....-the-300ms-click-delay
stopImmediatePropagation 和 stopPropagation 的區別:http://segmentfault.com/q/1010000000120125
也來說說touch事件與點擊穿透問題:http://segmentfault.com/a/1190000003848737
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/78495.html
摘要:為什么安卓可以正常工作代碼在剛運行的時候,就判斷是否需要使用,我的安卓測試機大于且設置了。所以在安卓下我點擊使用的原生事件當然沒問題。在第二次手動事件中,因為此時為,所以在中返回,接著從而順利觸發了原生事件。 在昨天的一個移動端項目中引入fastclick后手動觸發click事件失敗,查看了文檔也沒有找到解決的辦法,最后通過看fastclick源碼才解決。如果不想看中間這么多文字,可以...
摘要:源碼分析不愿意下代碼的可以直接點這里地址首先贊一下的代碼注釋,非常全。屬性一個對象,包含了代表所有從上一次觸摸事件到此次事件過程中,狀態發生了改變的觸點的對象。 所謂 zepto 的 touch 其實就是指這個文件啦,可以看到區區 165 行(包括注釋)就完成了 swipe 和 tap 相關的事件實現。在正式開始分析源碼之前,我們先說說 touch 相關的幾個事件,因為無論是 tap ...
摘要:移動端觸摸點擊事件優化源碼學習最近在做一些微信移動端的頁面,在此記錄關于移動端觸摸和點擊事件的學習優化過程,主要內容圍繞展開。當指針設備通常指鼠標在元素上移動時事件被觸發。移動端有延遲問題,可沒有哦。 移動端觸摸、點擊事件優化(fastclick源碼學習) 最近在做一些微信移動端的頁面,在此記錄關于移動端觸摸和點擊事件的學習優化過程,主要內容圍繞fastclick展開。fastclic...
摘要:移動端觸摸點擊事件優化源碼學習最近在做一些微信移動端的頁面,在此記錄關于移動端觸摸和點擊事件的學習優化過程,主要內容圍繞展開。當指針設備通常指鼠標在元素上移動時事件被觸發。移動端有延遲問題,可沒有哦。 移動端觸摸、點擊事件優化(fastclick源碼學習) 最近在做一些微信移動端的頁面,在此記錄關于移動端觸摸和點擊事件的學習優化過程,主要內容圍繞fastclick展開。fastclic...
閱讀 3569·2021-11-25 09:43
閱讀 3149·2021-10-08 10:04
閱讀 1636·2019-08-26 12:20
閱讀 2068·2019-08-26 12:09
閱讀 611·2019-08-23 18:25
閱讀 3582·2019-08-23 17:54
閱讀 2339·2019-08-23 17:50
閱讀 815·2019-08-23 14:33