点击穿透事件原因及解决办法

移动端touch事件穿透原因及解决办法

2007 年初。苹果公司在发布首款 iPhone 前夕,遇到一个问题:当时的网站都是为大屏幕设备所设计的。于是苹果的工程师们做了一些约定,应对 iPhone 这种小屏幕浏览桌面端站点的问题。这当中最出名的,当属双击缩放(double tap to zoom),这也是会有上述 300 毫秒延迟的主要原因。双击缩放,顾名思义,即用手指在屏幕上快速点击两次,iOS 自带的 Safari 浏览器会将网页缩放至原始比例。 那么这和 300 毫秒延迟有什么联系呢? 假定这么一个场景。用户在 iOS Safari 里边点击了一个链接。由于用户可以进行双击缩放或者双击滚动的操作,当用户一次点击屏幕之后,浏览器并不能立刻判断用户是确实要打开这个链接,还是想要进行双击操作。因此,iOS Safari 就等待 300 毫秒,以判断用户是否再次点击了屏幕。

click是在移动端有300ms的延迟,混用click和touch会导致穿透事件。

1.蒙层穿透

蒙层绑定了touch事件,而被蒙层覆盖的元素绑定的是click(或者tap,只要这个事件有延迟,都会发生),touch事件触发后,蒙层消失,300ms后由于“原先遮挡在前面的蒙层消失了”,click事件就落到了 被覆盖的元素上面

2.跨页面点击穿透

前面说的是被覆盖的元素添加了click事件,如果被覆盖的元素没有绑定click,而是一个a链接,或者是input输入框,也会发生穿透(a链接默认就有click跳转事件)

解决办法一:设置蒙层消失的延迟

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

$('.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 | visiblePainted | visibleFill | visibleStroke | visible | painted | fill | stroke | all | inherit;

pointer-events 属性有很多值,有用的主要是 auto 和 none,其他属性为 SVG 服务。

属性含义
auto 默认值,鼠标或触屏事件不会穿透当前层
none 元素不再是target,监听的元素变成了下层的元素(如果子元素设置成 auto,点击子元素会继续监听事件)
$('.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的延迟,也没有穿透问题

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

原生js初始化

if ('addEventListener' in document) {
    document.addEventListener('DOMContentLoaded', function() {
        FastClick.attach(document.body);
    }, false);
}

zepto初始化

FastClick.attach(document.body);

上面的FastClick.attach(document.body);传递的是body元素,代表body元素包括它的子元素都效果,如果想要部分dom元素有这个效果,可以换成相应的don元素

//直接使用click绑定
$('.mask').on('click',function(){
    console.log('mask-click');
    $(this).css('display','none');
})
解决办法四:
在上层的布局中增加android:clickable="true"的属性,这样下层的事件就不会被触发了。
posted @ 2019-06-27 09:44  一粒一世界  阅读(11001)  评论(0编辑  收藏  举报