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
来阻挠其他点击事宜的回调函数的实行,防备ghost click
的征象onMouse中,防备点透等诡异征象的代码
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
绑定了回调函数,假如有读取出来,运用addEventListener
,绑定事宜处置惩罚函数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; }
触发click流程
onTouchStart()
当一些更高级别的事宜发作的时刻(如电话接入或许弹出信息)会作废当前的touch操纵,即触发ontouchcancel。平常会在ontouchcancel时停息游戏、存档等操纵。因而在调试的时刻才会在touchStart以后,就触发了touchCancel
直接断点touchend
,在控制台打印,能够看到touchstart
也是触发的了、
推断是不是是单点触发
if (event.targetTouches.length > 1) { return true; }
猎取目的对象和
touch
事宜对象targetElement = this.getTargetElementFromEventTarget(event.target); touch = event.targetTouches[0];
依据
touch
事宜对象,设置一些初始属性this.trackingClick = true; //标识跟踪该次点击 this.trackingClickStart = event.timeStamp;//点击最早的时刻 this.targetElement = targetElement;//目的元素 this.touchStartX = touch.pageX; //x坐标 this.touchStartY = touch.pageY; //y坐标
onTouchMove()
假如刚触发完touchstart事宜立时就触发touchend,申明手指只是悄悄点了一下屏幕,也就是所谓的点击操纵。如许纵然不监听click事宜也能完成点击的侦听。不过这里有一个现实的状况,许多山寨的Android装备屏幕很不敏锐,须要用力按下才有所感知。这类状况下一定会触发touchmove事宜。所以针对Android装备的点击操纵能够恰当放宽,比方touchstart和touchend之间能够许可有少许几个touchmove,而且touchmove的间隔不能超过多少个像素等等
因而也是须要监听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的时刻,实行this.onTouchEnd(上个流程绑定了)
推断是不是在追踪该click,在this.onTouchMove的时刻,假如挪动的间隔大于边境,则将this.trackingClick=false,在touchend就不必再推断是不是为一个click的行动
if(!this.trackingClick){ return true; }
猎取目的元素标签,须要依据标署名来做一些推断
targetTagName = targetElement.tagName.toLowerCase();
假如是
label
,举行bug修复实行
this.needsFocus
,针对表单元素的focus和click事宜的处置惩罚先focus表单
在触发点击事宜
针对IOS,转动层bug修复
推断元素是不是须要原生的click,现实上就是有些行动照样要浏览器来实行默许的行动
表单元素
disabled
,点击不了type=file
的控件video
label
假如不须要,则发送一个click事宜
event.preventDefault(); this.sendClick(targetElement, event);
sendClick()流程
在一些安卓装备上,必需让一个元素
blured
,才使建立的clickEvent
见效if (document.activeElement && document.activeElement !== targetElement) { document.activeElement.blur(); }
建立
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);
建立完成以后,给予对象一个分外的属性,在
onClick
中能够运用,然后触发点击事宜,此时经由过程addEventListner
绑定的click
事宜就会触发clickEvent.forwardedTouchEvent = true; targetElement.dispatchEvent(clickEvent);
onClick()
addEventListener增加会根据增加递次实行
onClick作为第一个注册监听的,因而,是第一个实行的click
事宜的回调函数
特殊状况处置惩罚,平常不会实行
/* 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; }
实行
onMouse
,//建立时,附带的一个属性 if (event.forwardedTouchEvent) { return true; }
末了返回为真
return permitted; //true
注重:在这里的return
的true或false并不会影响绑定的其他回调函数的实行
总结
完整的看完代码,深深感觉到挪动端的坑异常的多,很有奇异的征象由于没有遇到过临时明白不了,愿望以后能够继承研讨,把代码完整读懂。