问题
在做手机页面的时候,遇到这样一个问题:
点击抽奖后,会出现一个弹框,点击弹框上的"确定"按钮,这时问题出现了,当确定按钮和下边的抽奖按钮重合时,弹框隐藏,并且同时触发了抽奖按钮!!!
这时就了解到:什么是事件穿透?点击上面的一层时会触发下面一层的事件。
zepto的tap是通过兼听绑定在document上的touch事件来完成tap事件的模拟的,tap事件是冒泡到document上触发的。
在点击完成时的tap事件(touchstart/touchend)需要冒泡到document上才会触发。
而在冒泡到document之前,用户手的接触屏幕(touchstart)和离开屏幕(touchend)是会触发click事件 的,因为click事件有延迟触发 (这就是为什么移动端不用click而用tap的原因)(大概是300ms,为了实现safari的双击事件的设计)。
所以在执行完tap事件之后,弹出来的选择组件马上就隐藏了,此时click事件还在延迟的300ms之中,当300ms到来的时候,click到的其实不是完成而是隐藏之后的下方的元素,如果正下方的元素绑定的有click事件此时便会触发,如果没有绑定click事件的话就当没click,但是正下方的是input输入框(或者select选择框或者单选复选框),点击默认聚焦而弹出输入键盘,也就出现了上面的点透现象。
解决
- 监听touchend事件,并在事件中使用
preventDefault() 阻止冒泡。
$(".close").on("touchend", function(e){ //这里使用touchstart事件也可以
e.preventDefault();
//do something...
});
- 延迟一定的时间来处理事件。本人测试是超过320毫秒就不会出现穿透,与jquery的动画(fadeIn(),fadeOut())等配合,感觉良好;
$(id).fadeIn(300);
- 如果还不奏效,终极解决方案是用click替代tap;
//设置点击事件为_tap
_tap = touchend in document ? "touchend":"click"
//这样在执行的过程中就可以直接调用
div.on(_tap, function(){...})
- 使用css3的pointer-events=true,pointer-events=none切换来实现
对pointer-events这个属性进行简单介绍:设置或检索在何时成为属性事件的target。
使用pointer-events来阻止元素成为鼠标事件目标不一定意味着元素上的事件侦听器永不会触发。
如果元素后代明确指定了pointer-events属性并允许其成为鼠标事件的目标,
那么指向该元素的任何事件在事件传播过程中都将通过父元素,并以适当的方式触发其上的事件侦听器。
当然位于屏幕上在父元素上但不在后代元素上的鼠标活动都不会被父元素和后代元素捕获(将会穿过父元素而指向位于其下面的元素)。
补充
我们往往用a标签来写一些按钮等,如何阻止a的链接跳转呢?
disabled的属性是一个禁止功能,但是在a标签下不能真正的工作,在a标签内只有没有herf和pointer-events:none时,才能真正的禁用事件,无论是鼠标事件还是keyup事件。
附
阻止点击穿透常用于移动端禁止触摸滚动