移动端的点击穿透问题

1、概况

说完移动端点击300ms延迟的问题,还不得不提一下移动端点击穿透的问题。可能有人会想,既然cick点击有300ms的延迟,那对于触摸屏,我们直接监听 touchstart事件不就好了吗?
使用 touchstart去代替click事件有两个不好的地方。

  • 1、touchstart昰指触摸屏幕就触发,有时候用户只是想滑动屏幕,却触发了 touchstart事件,这不是我们想要的结果。
  • 2、使用 touchstart事件在某些场景下可能会出现点击穿透的现象。

什么是点击穿透?
假如页面上有两个元素A和B,B元素在A元素之上,B为遮罩层mask。我们在B元素上绑定 touchstart事件,作用是隐藏B元素;A元素上绑定click事件。我们发现,当我们点击B元素,B元素被隐藏了,随后,也触发了A元素的click事件。

点击穿透的原因
这是因为在移动端浏览器,事件执行的顺序是 touchstart ==>touchmove==>touched ==>click。而click事件有300ms的延迟,当 touchstart事件把B元素隐藏之后,隔了300ms,浏览器触发了click事件,但是此时B元素不见了,所以该事件被派发到了A元素身上。如果A元素是一个链接,那此时页面就会意外地跳转了。

2、解决点击穿透问题的办法

办法一:延迟上层元素的消失

touchstart后延迟350ms再隐藏mask。先把透明度设置为0,解决视觉层面的效果,在设置定时器延迟,让A元素消失。

$('.mask').on('touchstart',function() {
    console.log('mask-touchstart');
    $(this).css('opacity', 0);
    setTimeout(function() {
        $('.mask').css('dispaly', 'none');
    },350);
})

办法二:pointer-events,让被覆盖元素短时间内无法触发click

有必要介绍一个 CSS3 的属性 —— pointer-events。
pointer-events 属性

  • auto:默认值,鼠标或触屏事件不会穿透当前层
  • none:使元素无法触发事件
$('.mask').on('touchstart',function() {
    console.log('mask-touchstart');
    $(this).css('display', 'none');
    //让被覆盖元素无法响应click
    $('.box').css('pointer-events', 'none');
    //恢复被覆盖元素
    setTimeout(function() {
        $('.box').css('pointer-events', 'auto');
    },300);
})

办法三:使用fastclick库

使用fastclick库,从此所有的点击事件都使用click,没有300ms的延迟,也没有穿透问题

//1、引入fastclick
<script src="js/fastclick.min.js"></script>

//2、原生js初始化
if ('addEventListener' in document) {
    document.addEventListener('DOMContentLoaded', function() {
        FastClick.attach(document.body);
    }, false);
}

//3、直接像往常一样,调用即可
 var div = document.querySelector('div');
 div.addEventListener('click',function(){
     alert(111);
 })

办法四:针对安卓的,android:clickable="true"

在上层的布局中增加android:clickable="true"的属性,这样下层的事件就不会被触发了。

参考链接:https://www.cnblogs.com/leftJS/p/11095226.html

上一篇:Vue面试/学习基础知识


下一篇:jQuery 选择器