浅谈FastClick 填坑及源码解析(3)
基本上都是一些能禁用 300ms 时延的浏览器嗅探,它们都没必要使用 Fastclick,所以会返回 true 回构造函数停止下一步执行。
由于安卓手Q的 ua 会被匹配到 /Chrome\/([0-9]+)/,故带有 'user-scalable=no' meta 标签的安卓手Q页会被 FastClick 视为无需处理页。
这也是为何在安卓手Q里没有开头提及问题的原因。
我们继续看构造函数,它直接给 layer(即body)添加了click、touchstart、touchmove、touchend、touchcancel(若是安卓还有 mouseover、mousedown、mouseup)事件监听:
//安卓则做额外处理 if (deviceIsAndroid) { layer.addEventListener('mouseover', this.onMouse, true); layer.addEventListener('mousedown', this.onMouse, true); layer.addEventListener('mouseup', this.onMouse, true); } layer.addEventListener('click', this.onClick, true); layer.addEventListener('touchstart', this.onTouchStart, false); layer.addEventListener('touchmove', this.onTouchMove, false); layer.addEventListener('touchend', this.onTouchEnd, false); layer.addEventListener('touchcancel', this.onTouchCancel, false);
注意在这段代码上面还利用了 bind 方法做了处理,这些事件回调中的 this 都会变成 Fastclick 实例上下文。
另外还得留意,onclick 事件以及安卓的额外处理部分都是走的捕获监听。
咱们分别看看这些事件回调分别都做了什么。
1. this.onTouchStart
FastClick.prototype.onTouchStart = function(event) { var targetElement, touch, selection; // 多指触控的手势则忽略 if (event.targetTouches.length > 1) { return true; } targetElement = this.getTargetElementFromEventTarget(event.target); //一些较老的浏览器,target 可能会是一个文本节点,得返回其DOM节点 touch = event.targetTouches[0]; if (deviceIsIOS) { //IOS处理 // 若用户已经选中了一些内容(比如选中了一段文本打算复制),则忽略 selection = window.getSelection(); if (selection.rangeCount && !selection.isCollapsed) { return true; } if (!deviceIsIOS4) { //是否IOS4 //怪异特性处理——若click事件回调打开了一个alert/confirm,用户下一次tap页面的其它地方时,新的touchstart和touchend //事件会拥有同一个touch.identifier(新的 touch event 会跟上一次触发alert点击的 touch event 一样), //为避免将新的event当作之前的event导致问题,这里需要禁用事件 //另外chrome的开发工具启用'Emulate touch events'后,iOS UA下的 identifier 会变成0,所以要做容错避免调试过程也被禁用事件了 if (touch.identifier && touch.identifier === this.lastTouchIdentifier) { event.preventDefault(); return false; } this.lastTouchIdentifier = touch.identifier; // 如果target是一个滚动容器里的一个子元素(使用了 -webkit-overflow-scrolling: touch) ,而且满足: // 1) 用户非常快速地滚动外层滚动容器 // 2) 用户通过tap停止住了这个快速滚动 // 这时候最后的'touchend'的event.target会变成用户最终手指下的那个元素 // 所以当快速滚动开始的时候,需要做检查target是否滚动容器的子元素,如果是,做个标记 // 在touchend时检查这个标记的值(滚动容器的scrolltop)是否改变了,如果是则说明页面在滚动中,需要取消fastclick处理 this.updateScrollParent(targetElement); } } this.trackingClick = true; //做个标志表示开始追踪click事件了 this.trackingClickStart = event.timeStamp; //标记下touch事件开始的时间戳 this.targetElement = targetElement; //标记touch起始点的页面偏移值 this.touchStartX = touch.pageX; this.touchStartY = touch.pageY; // this.lastClickTime 是在 touchend 里标记的事件时间戳 // this.tapDelay 为常量 200 (ms) // 此举用来避免 phantom 的双击(200ms内快速点了两次)触发 click // 反正200ms内的第二次点击会禁止触发其默认事件 if ((event.timeStamp - this.lastClickTime) < this.tapDelay) { event.preventDefault(); } return true; };
内容版权声明:除非注明,否则皆为本站原创文章。