touch事件的来源
- pc mousedown -> mouseup -> mousemove
- 移动端 touchstart -> touchmove -> touchend
参数获取
- touches 屏幕中每根手指信息列表
- targetTouches 和touch类似,把同一节点的手指信息过滤掉
- changedTouches 响应当前时间的每根手指的信息列表

说明:在手机上,当我们手触碰屏幕时,要过300ms左右才会触发mousedown事件,所以click事件在手机上看起来就像慢半拍一样
移动端click 300ms 延迟
注意:user-scalable=no 设置了这个属性之后也就不存在点击300ms延迟的问题了
基本描述
1.问题由来:
这要追溯至 2007 年初。苹果公司在发布首款 iPhone 前夕,遇到一个问题:当时的网站都是为大屏幕设备所设计的。于是苹果的工程师们做了一些约定,应对 iPhone 这种小屏幕浏览桌面端站点的问题。 这当中最出名的,当属双击缩放(double tap to zoom),这也是会有上述 300 毫秒延迟的主要原因。双击缩放,顾名思义,即用手指在屏幕上快速点击两次,iOS 自带的 Safari 浏览器会将网页缩放至原始比例。
那么这和 300 毫秒延迟有什么联系呢? 假定这么一个场景。用户在 iOS Safari 里边点击了一个链接。由于用户可以进行双击缩放或者双击滚动的操作,当用户一次点击屏幕之后,浏览器并不能立刻判断用户是确实要打开这个链接,还是想要进行双击操作。因此,iOS Safari 就等待 300 毫秒,以判断用户是否再次点击了屏幕。 鉴于iPhone的成功,其他移动浏览器都复制了 iPhone Safari 浏览器的多数约定,包括双击缩放,几乎现在所有的移动端浏览器都有这个功能。之前人们刚刚接触移动端的页面,在欣喜的时候往往不会care这个300ms的延时问题,可是如今touch端界面如雨后春笋,用户对体验的要求也更高,这300ms带来的卡顿慢慢变得让人难以接受。
2.简单总结:移动端为了展示pc端页面给用户一个放大网页的方式,所以浏览器需要判断用户的点击行为
3.代码测试:
解决方案
fastclick
实现原理:fastclick 在检测到touchend事件的时候,会通过dom自定义事件立即触发一个模拟click事件,并把浏览器在300毫秒之后真正触发的click事件阻止掉。
FastClick 的使用方法非常简单,在 window load 事件之后,在body上调用FastClick.attach()即可。
window.addEventListener( "load", function() {FastClick.attach( document.body );}, false );
attach方法虽可在更具体的元素上调用,直接绑定到body上可以确保整个应用都能受益。当 FastClick 检测到当前页面使用meta设置了user-scalable=no或者 touch-action 属性的解决方案时,会静默退出。可以说,这是真正的跨平台方案出来之前一种很好的变通方案。
就目前而言,FastClick 非常实际地解决 300 毫秒点击延迟的问题,唯一的缺点可能也就是该脚本的文件尺寸 (尽管它只有10kb)。如果你连这10kb都接受不了的话,那么移动端类库 jQuery和zepto.js都支持tap事件来解决这个问题,尽管它们的响应速度比FastClick慢一些。
穿透场景
问题说明
当有一个绝对定位或固定定位元素绑定了touch事件,那么覆盖在他只下的具有点击特性的元素也会被触发。
弹窗/浮层这种形式。当点击关闭之后,touchend首先触发tap,弹出层关闭。但是touchend后继续等待300ms发现没有其他行为了,则继续触发click,由于这时弹出层已经消失,所以当前click事件的target就在底层元素上,于是就触发了底部。整个事件触发过程为 touchend -> tap -> click。

原因:touch会先于click事件执行,当上述的这个遮罩层消失在300ms之内,那么他底下的具有点击特性的元素会被触发
代码实现 弹窗/浮层。比如:有一个遮罩层A元素,他的底下有一个链接元素B. 当这个遮罩层点击之后希望遮罩层消失,真实的状况是这时候点击遮罩层不见的同时会跳转页面。
解决方案:
- 可以在touch阶段取消掉触发的click事件
- 可以让消失的元素延迟 200-300ms ```javascript
<!DOCTYPE HTML>
<style type="text/css">body{margin: 0;}.container{width: 100%;overflow: hidden;position: relative;}.layer-title{width: 100%;margin: 50px 0;text-align: center;}.layer-action{position: absolute;bottom: 20px;width: 100%;text-align: center;}.btn{background-color: #08c;border: 0;color: #fff;height: 30px;line-height: 30px;width: 100px;}#underLayer{background-color: #eee;width: 90%;height: 500px;line-height: 500px;margin: 30px auto 1000px;text-align: center;}#popupLayer{/*display: none;*/background-color: #fff;width: 80%;height: 200px;position: fixed;top: 50%;left: 50%;margin-left: -40%;margin-top: -100px;z-index: 1;}#bgMask{position: fixed;top: 0;left: 0;right: 0;bottom: 0;background-color: rgba(0,0,0,0.6);}</style>
<div id="popupLayer"><div class="layer-title">弹出层</div><div class="layer-action"><button class="btn" id="closePopup">关闭</button></div></div></div><div id="bgMask"></div><script type="text/javascript" src="//cdn.bootcss.com/zepto/1.0rc1/zepto.min.js"></script><script type="text/javascript">Zepto(function($){// 点击穿透var $close = $('#closePopup');var $popup = $('#popupLayer');var $under = $('#underLayer');var $mask = $('#bgMask');$close.on('tap', function(e){$popup.hide();$mask.hide();});$under.on('click', function(){alert('underLayer clicked');});});</script>
``` **
tips:
- 遮罩的形成注意需要给 一个 z-index 这样才可以实现下面是透明的效果
解决方案:
poniter-events 主要属性 auto 和 none
文章
