1. 穿透问题可这么理解, 共有2种问题:
问题1: 有A 和 B 两个弹层,B 弹层盖在A 弹层上面,B 弹层绑定 touchend 事件,当用户点击B 的时候 B隐藏,由于touchend 事件触发的太快了,导致用户点击到弹层下面的具有click 属性的元素的东东。(包括 A 标签<a href='#'></a> 或 input 框 或 绑定了 click 事件的元素)
奇怪的是, 若给链接A 绑定了touchend 并且e.preventDefault() 也是不起作用。请看下面的例子,也就是它根本没有执行 touchend 事件,但是却执行了A 元素的 href 跳转链接。
<a href='https://www.baidu.com/'></a> <script type='text/javascript'> // B 是在 a 链接上面的弹层 B.on('touchend', function(){ B.hide(); }); // 大部分浏览器都不会执行 console.log,但是 ios 8.4 safari 不跳转,因为它本来就没有穿透问题。 $('a').on('touchend', function(e){ console.log('touchend'); e.preventDefault(); }); </script>
浏览器表现 :
ios 8.4 safari 页面不跳转
ios 8.4 UC 10.6.5.627 跳转
ios 7.0 safari 跳转
ios 7.0 UC 10.6.5.627 跳转
SAMSUNG GT-19308 4.3 UC 10.6.5.627 跳转
SAMSUNG GT-19308 4.3 跳转。 若直接点击链接 a,竟然会跳转,e.preventDefault() 竟然没作用,只有这个浏览器会。想点击 a 链接不跳转,只能绑定 click 事件并且 e.preventDefault();
问题2:有A 和 B两个元素,B 元素盖在A 元素上面,B元素默认隐藏。A元素绑定事件让B 元素显示出来,B元素点击自己隐藏。出现的现象是: 点击A元素 B元素显示不出,因为触发了B元素里的代码。
A.on('touchend', function(){ B.show(); }); // 就算B 元素用 touchend 绑定, 有的手机也还是会触发 B.hide(); B.on('click', function(){ B.hide(); });
解决穿透问题1:
各个浏览器的表现
iOS 8.4 safari用touchend 关闭 不会穿透下面绑定的 click 事件, 所以什么事都不用做,很完美。
iOS 8.4 和 iOS 7.0 UC浏览器弹窗关闭用 setTimeout(function(){ 弹层.hide() }, 0); 可以解决弹层穿透。
另外备注下: UC 浏览器做过优化,下面的代码 click 事件比 touchend的触发的快。
$('.m').on('touchend', function(){ setTimeout(function(){ console.log('touchend'); }, 0); }); $('.m').click(function(){ console.log('click'); });
iOS 7.0 safari的不行,只能用 e.preventDefault() 解决 或者设置 setTimeout(.. 360),而 e.preventDefault() 也支持 ios8.4 safari和UC版本的。
Android 的手机 4.1.1 JRO03L MIUI-JLB14.0, e.preventDefault();不能解决,但是 setTiemout 只要在 >=300 就可以解决了。
所以最终的解决办法:
由于 iOS 7.0上 setTimeout 360毫秒 的时间太长了,所以直接给 B弹层绑定 e.preventDefault();
B.on('touchend', function(e){ e.preventDefault(); B.hide(); });
Android上解决方式通过属性 pointer-events: none; 让整个页面都不能有点击的属性, 301秒以后恢复属性值。
B.on('touchend', function(){ $('html').css({ pointer-events: 'none' }); setTimeout(function(){ $('html').css({ pointer-events: 'auto' }); }, 301); B.hide(); });
解决穿透问题2:
解决方式比较简单, A 里面用 e.preventDefault(), 注意A也不能绑定tap; B 绑定 touchend
A.on('touchend', function(e){ e.preventDefault(); B.show(); }); B.on('touchend', function(){ B.hide(); });
2. 当给一个元素绑定 touchend 事件和click事件, touchend事件让元素关闭,那么都不会触发到 click 事件,浏览器如下。
SAMSUNG GT-19308 4.3 原生浏览器 和 UC浏览器 10.6.5.627
IOS7.0 safari 和 UC浏览器 10.6.5.627
IOS8.4 safari 和 UC浏览器 10.6.5.627
3. fastClick
通过绑定 body touchend,然后通过逻辑找到 e.target 元素,满足条件下执行 e.preventDefault(); 阻止了 click事件,然后让 initMouseEvent 和 dispatchEvent 来触发。
问题1的是否解决 的浏览器兼容如下:
SAMSUNG GT-19308 4.3 和 ios8.4
原生浏览器和safari 可以
UC浏览器都 可以
ios7.0 safri 和 UC浏览器 都不可以
4. 注意:若给 html 根元素绑定了
$('html').on('touchend', function(){ e.preventDefault(); })
则页面里所有的元素 click 绑定的事件都触发不了, input 都不能点击输入了。