摘要:一直好奇是如何工作,于是花了幾天空余的時間一步步調試代碼,學習。一般會在時暫停游戲存檔等操作。這樣即使不監(jiān)聽事件也能實現(xiàn)點擊的偵聽。這種情況下一定會觸發(fā)事件。
Patience and perseverance will get paid.
這段時間開始實習了,在公司做hybrid,專職寫js,學習到了不少東西。一直好奇fastclick是如何工作,于是花了幾天空余的時間一步步調試代碼,學習fastclick。這篇文章可以結合者代碼看,希望可以給予需要學習fastclick的人一點思路。
有錯誤的地方希望指正,thk~
主流程FastClick.attach()
FastClick(layer)
初始化化變量
this.trackingClick = false; //追蹤一個click this.trackingClickStart = 0; //追蹤時間 this.targetElement = null; // 目標元素 this.touchStartX = 0;// X坐標 this.touchStartY = 0;// y坐標 this.lastTouchIndentifier = 0; this.touchBoundary = 10;//邊界條件(是否是一個點擊) this.layer = layer;//layer可以是document.body/document.documentElement
安卓設備綁定鼠標事件(在捕獲階段,為的是第一時間處理到事件)
layer.addEventListener("mouseover",bind(this.onMouse,this),true); layer.addEventListener("mousedown",bind(this.onMouse,this),true); layer.addEventListener("mouseup",bind(this.onMouse,this),true);
綁定touch和click事件(判定是否是click行為,取消之前的click),
//最先捕獲到 layer.addEventListener("click", bind(this.onClick, this), true); //冒泡階段捕獲 layer.addEventListener("touchstart", bind(this.onTouchStart, this), false); layer.addEventListener("touchmove", bind(this.onTouchMove, this), false); layer.addEventListener("touchend", bind(this.onTouchEnd, this), false); layer.addEventListener("touchcancel", bind(this.onTouchCancel, this), false);
判斷是否存在stopImmediatePropagation,如果不存在則進行hack,在onMouse中會利用stopImmediatePropagation來阻止其他點擊事件的回調函數(shù)的執(zhí)行,避免ghost click的現(xiàn)象
onMouse中,防止點透等詭異現(xiàn)象的代碼
if (!this.needsClick(this.targetElement) || this.cancelNextClick) { // Prevent any user-added listeners declared on FastClick element from being fired. if (event.stopImmediatePropagation) { event.stopImmediatePropagation(); } else { // Part of the hack for browsers that don"t support Event#stopImmediatePropagation (e.g. Android 2) event.propagationStopped = true; } // Cancel the event event.stopPropagation(); event.preventDefault(); return false; }
判斷是否通過onclick綁定了回調函數(shù),如果有讀取出來,使用addEventListener,綁定事件處理函數(shù)
if (typeof layer.onclick === "function") { // Android browser on at least 3.2 requires a new reference to the function in layer.onclick // - the old one won"t work if passed to addEventListener directly. oldOnClick = layer.onclick; layer.addEventListener("click", function (event) { oldOnClick(event); }, false); layer.onclick = null; }觸發(fā)click流程 onTouchStart()
當一些更高級別的事件發(fā)生的時候(如電話接入或者彈出信息)會取消當前的touch操作,即觸發(fā)ontouchcancel。一般會在ontouchcancel時暫停游戲、存檔等操作。因此在調試的時候才會在touchStart之后,就觸發(fā)了touchCancel
直接斷點touchend,在控制臺打印,可以看到touchstart也是觸發(fā)的了、
判斷是不是單點觸發(fā)
if (event.targetTouches.length > 1) { return true; }
獲取目標對象和touch事件對象
targetElement = this.getTargetElementFromEventTarget(event.target); touch = event.targetTouches[0];
根據(jù)touch事件對象,設置一些初始屬性
this.trackingClick = true; //標識跟蹤該次點擊 this.trackingClickStart = event.timeStamp;//點擊開始的時間 this.targetElement = targetElement;//目標元素 this.touchStartX = touch.pageX; //x坐標 this.touchStartY = touch.pageY; //y坐標onTouchMove()
如果剛觸發(fā)完touchstart事件馬上就觸發(fā)touchend,說明手指只是輕輕點了一下屏幕,也就是所謂的點擊操作。這樣即使不監(jiān)聽click事件也能實現(xiàn)點擊的偵聽。不過這里有一個實際的情況,很多山寨的Android設備屏幕很不靈敏,需要使勁按下才能有所感知。這種情況下一定會觸發(fā)touchmove事件。所以針對Android設備的點擊操作可以適當放寬,比如touchstart和touchend之間可以允許有少量幾個touchmove,并且touchmove的距離不能超過多少個像素等等
因此也是需要監(jiān)聽onTouchMove,并且加入判斷
// If the touch has moved, cancel the click tracking if ( this.targetElement !== this.getTargetElementFromEventTarget(event.target) || this.touchHasMoved(event) ) { this.trackingClick = false; this.targetElement = null; }onTcouhEnd()
在touchend的時候,執(zhí)行this.onTouchEnd(上個流程綁定了)
判斷是否在追蹤該click,在this.onTouchMove的時候,如果移動的距離大于邊界,則將this.trackingClick=false,在touchend就不用再判斷是否為一個click的行為
if(!this.trackingClick){ return true; }
獲取目標元素標簽,需要根據(jù)標簽名來做一些判斷
targetTagName = targetElement.tagName.toLowerCase();
如果是label,進行bug修復
執(zhí)行this.needsFocus,針對表單元素的focus和click事件的處理
先focus表單
在觸發(fā)點擊事件
針對IOS,滾動層bug修復
判斷元素是否需要原生的click,實際上就是有些行為還是要瀏覽器來執(zhí)行默認的行為
表單元素disabled,點擊不了
type=file的控件
video
label
如果不需要,則發(fā)送一個click事件
event.preventDefault(); this.sendClick(targetElement, event);sendClick()流程
在一些安卓設備上,必須讓一個元素blured,才能使創(chuàng)建的clickEvent生效
if (document.activeElement && document.activeElement !== targetElement) { document.activeElement.blur(); }
創(chuàng)建clickEvent,使用touch事件對象的屬性來進行初始化
clickEvent = document.createEvent("MouseEvents"); clickEvent.initMouseEvent( this.determineEventType(targetElement), //bug修復針對select true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);
創(chuàng)建完成之后,賦予對象一個額外的屬性,在onClick中可以使用,然后觸發(fā)點擊事件,此時通過addEventListner綁定的click事件就會觸發(fā)
clickEvent.forwardedTouchEvent = true; targetElement.dispatchEvent(clickEvent);onClick()
addEventListener添加會按照添加順序執(zhí)行
onClick作為第一個注冊監(jiān)聽的,因此,是第一個執(zhí)行的click事件的回調函數(shù)
特殊情況處理,一般不會執(zhí)行
/* It"s possible for another FastClick-like library delivered with third- party code to fire a click event before FastClick does (issue #44). In that case, set the click-tracking flag back to false and return early. This will cause onTouchEnd to return early. */ if (this.trackingClick) { this.targetElement = null; this.trackingClick = false; return true; }
特殊情況處理
if (event.target.type === "submit" && event.detail === 0) { return true; }
執(zhí)行onMouse,
//創(chuàng)建時,附帶的一個屬性 if (event.forwardedTouchEvent) { return true; }
最后返回為真
return permitted; //true
注意:在這里的return的true或false并不會影響綁定的其他回調函數(shù)的執(zhí)行
總結完整的看完代碼,深深感覺到移動端的坑非常的多,很有怪異的現(xiàn)象因為沒有遇到過暫時理解不了,希望之后可以繼續(xù)研究,把代碼完全讀懂。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/79839.html
摘要:前言最近公司新開了一條業(yè)務線,有幸和大佬們一起從頭開始構建一套適合新業(yè)務的框架。俗話說得好呀,適合自己的才是最好的 前言 最近公司新開了一條業(yè)務線,有幸和大佬們一起從頭開始構建一套適合新業(yè)務的框架。俗話說得好呀,適合自己的才是最好的
摘要:前言最近公司新開了一條業(yè)務線,有幸和大佬們一起從頭開始構建一套適合新業(yè)務的框架。俗話說得好呀,適合自己的才是最好的前言 (Foreword) 最近公司新開了一條業(yè)務線,有幸和大佬們一起從頭開始構建一套適合新業(yè)務的框架。俗話說得好呀,適合自己的才是最好的
閱讀 1394·2021-11-08 13:14
閱讀 747·2021-09-23 11:31
閱讀 1038·2021-07-29 13:48
閱讀 2781·2019-08-29 12:29
閱讀 3371·2019-08-29 11:24
閱讀 1899·2019-08-26 12:02
閱讀 3688·2019-08-26 10:34
閱讀 3435·2019-08-23 17:07