移动端事件触发顺序
- 在 touchstart ,touchmove 或者 touchend 事件中的任意一个调用 event.preventDefault(),
- 在触摸的过程中触发了 touchcancel 事件,后面的鼠标事件将不会被触发
touchstart
touchmove
touchend
mousemove
mousedown
mouseup
click
300 毫秒延迟原因
- 移动浏览器在 touchend 和 click 之间应用了300-350ms的延迟,以等待是否会出现双击缩放文本的手势
300 毫秒延迟产生的点击穿透问题
<div class="container">
<div id="underLayer">底层元素</div>
<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>
$('#closePopup').on('tap', function(e){
$('#popupLayer').hide();
$('#bgMask').hide();
});
$('#underLayer').on('click', function(){
alert('underLayer clicked');
});
- 点击关闭按钮,touchend 首先触发 tap,弹出层和遮罩就被隐藏了。touchend 后继续等待 300ms 发现没有其他行为了,则继续触发 click,而由于click事件的滞后性(300ms),在这 300ms 内上层元素隐藏或消失了,导致下层同样位置的 DOM 元素触发了click事件(如果是input框则会触发focus事件),看起来就像点击的target“穿透”到下层去了。
IOS的300毫秒延迟
- iOS 8 之前一直都是 UIWebView,iOS 8 出了个 WKWebView,UIWebView 300ms 延迟的问题到现在一直存在,哪怕是最新的 iOS 版本。
- WKWebView 在 iOS 9.3 的时候将这个问题给修复了。
禁用缩放
- Chrome on Android (all versions)、iOS 9.3
- Chrome 32 对移动端进行了优化,可以不禁用缩放,也能解决延迟的问题
<meta name="viewport" content="user-scalable=no" />
禁用双击缩放
html {
touch-action: manipulation;
-ms-touch-action: manipulation;
}
设置视口宽度
<meta name="viewport" content="width=device-width" />
fastclick 库
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1,minimum-scale=1, user-scalable=no" />
<script
src="https://as.alipayobjects.com/g/component/fastclick/1.0.6/fastclick.js">
</script>
<script>
if ('addEventListener' in document) {
document.addEventListener('DOMContentLoaded', function() {
FastClick.attach(document.body);
}, false);
}
if(!window.Promise) {
document.writeln('<script src="https://as.alipayobjects.com/g/component/es6-promise/3.2.2/es6-promise.min.js" '+'>'+'<'+'/'+'script>');
}
</script>
手动封装一个 tap 方法
function tap (obj,callback) {
var isMove = false;
var startTime = 0;
obj.addEventListener('touchstart',function(e){
startTime = Date.now();
})
obj.addEventListener('touchmove',function(e){
isMove = true;
})
obj.addEventListener('touchend',function(e){
if(!isMove && (Date.now()-statrTime) < 150){
callback && callback();
}
isMove = false;
startTime = 0;
})
};
tap(div,function(){
fastclick 原理
- 在 touchend 阶段 调用 event.preventDefault,然后通过 document.createEvent 创建一个 MouseEvents,然后 通过 eventTarget.dispatchEvent 触发对应目标元素上绑定的 click 事件