tap
在Web移动端,使用click
会有300ms的延迟时间。这是因为,浏览器在等着看你是不是在执行双击。这300ms延迟给带来了不好的用户体验,特别在切换选项卡的时候,会让人觉得是不是没有按到。
Zepto
的touch
模块的tap
事件解决了300ms的问题,页面的响应速度给人感觉快了,不过使用tap
事件却会带来其他问题,比如“点击穿透”。
什么是“点击穿透”?
“点击穿透”常见的发生场景:
假如页面上有A和B两个元素。B元素在A元素之上。我们在B元素的tap
事件上注册了一个回调函数,该回调函数的作用是隐藏B元素。这时,我们发现,当我们点击B元素,B元素被隐藏了,随后,A元素触发了click
事件。
为什么会发生“点击穿透”?
通过看Zepto
的touch.js
的源码,我发现tap
事件不是移动端原生的事件,而是通过绑定在document
上的底层touchstart
,touchmove
,touchend
,touchcancel
事件来封装实现的自定义事件,除了tap
还有其他的swipe
,doubleTap
,longTap
等自定义事件。
touchstart
和touchend
都是立即触发的,所以tap
事件的响应也会很快,这时候位于页面上层的B元素会很快隐藏。
但是click
事件有300ms的延迟,当tap
事件把B元素隐藏之后,隔了300ms,浏览器触发了click
事件,但是此时B元素不见了,所以该事件被派发到了B元素下的A元素上。
如果A元素没有绑定click
事件,往往页面不会有什么反应,不过如果A元素是一个a
元素,页面就会发生跳转;如果A元素是一个input
元素(或者select
),元素就会聚焦弹出键盘。
“点击穿透”的解决方法
只用tap
将页面所有click
事件全部换成tap
,这样就算发生“点击穿透”,因为页面没有绑定click
事件,所以对页面也不会有影响。不过a
元素还是会跳转,我们可以这样做:
$(function() { |
代码阻止了a
标签click
的默认行为,然后通过js来实现跳转。
不过上面这一招对input
元素(或者select
)不起作用,这些元素还是触发默认的行为。
tap延迟300ms+再隐藏元素
$('#hideDiv').on('tap', function(e) { |
这一招即使click
有300ms的延时,但是300ms后click
也是派发到当前元素上,而不会派发到下面的元素上。