由于移动设备的物理特性导致的。物理上,当用户在触摸屏幕时,设备需要时间来判断用户是要单击、双击或长按以及响应相应的事件,因此会存在一个300ms短暂的延迟。由于延迟的存在会导致一些问题的产生。
下面用一个小demo演示移动端点击穿透的问题,以及解决方法
1.首先在案例中设置两个盒子分别是top,bottom盒子
<div id="box">
<p class="top">X</p>
<p class="bottom"></p>
</div>
2.设置样式将top盒子置于bottom盒子的上方
* {
margin: 0;
padding: 0;
}
#box {
width: 100vw;
height: 100vh;
}
.top {
width: 40vw;
height: 20vh;
background-color: skyblue;
position: absolute;
top: 50px;
left: 100px;
cursor: pointer;
}
.bottom {
width: 100%;
height: 100%;
background-color: pink;
cursor: pointer;
}
3.获取dom元素并设置点击事件
const top1 = document.getElementsByClassName("top")[0],
btm = document.getElementsByClassName("bottom")[0];
top1.ontouchend = function (e) {
console.log("我准备关闭上层的按钮了");
top1.style.display = "none";
};
btm.onclick = function () {
console.log("我被点击了");
};
可以看到上层top盒子关闭的同时触发了下面的点击事件
解决的方法:
1. 第一种 通过执行e.preventDefault()阻止touchend事件的默认行为,
// 第一种 通过阻止touchend事件的默认行为,
// e.preventDefault()
top1.ontouchend = function (e) {
e.preventDefault()
console.log("我准备关闭上层的按钮了");
top1.style.display = "none";
};
btm.onclick = function () {
console.log("我被点击了");
};
运行点击上层元素只触发了top元素的事件,解决了手势穿透的问题
第二种 延迟300ms再关闭
setTimeout(()=>{
top1.style.display ="none";
},350)
因为click事件触发会在0.3s之后响应,延迟300ms执行遮罩层cover的隐藏, 那click响应时,btn还在,即相应给btn
第三种:使用插件 fastclick.js 防止手势穿透, 这个插件专为解决手势穿透现象而生
<script src="https://cdn.bootcdn.net/ajax/libs/fastclick/1.0.6/fastclick.js"></script>
FastClick.attach(document.body);
fastclick取消click事件300ms延迟的原理: fastclick监听了click事件的触发, 当body上触发了click事件时, fastclick会自定义一个事件,并立即触发, 并把监听到的系统click事件阻止掉