什么是 click 点透

先上一段代码,直观感受一下

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7. <title>Document</title>
  8. <style>
  9. * {
  10. margin: 0;
  11. padding: 0;
  12. }
  13. .content {
  14. background: #ccc;
  15. height: 1200px;
  16. }
  17. .modal {
  18. position: absolute;
  19. top: 50%;
  20. left: 50%;
  21. width: 300px;
  22. height: 250px;
  23. background: #f30;
  24. transform: translate3d(-50%, -50%, 0);
  25. }
  26. </style>
  27. </head>
  28. <body>
  29. <div id="app">
  30. <div id="js-content" class="content">我是内容 - B</div>
  31. <div id="js-modal" class="modal">我是弹窗 - A</div>
  32. </div>
  33. <script>
  34. var $content = document.getElementById('js-content');
  35. var $modal = document.getElementById('js-modal');
  36. $modal.addEventListener('touchstart', function(e) {
  37. $modal.style.display = 'none';
  38. alert('$modal touchstart');
  39. });
  40. $modal.onclick = function() {
  41. alert('$modal click');
  42. }
  43. $content.onclick = function() {
  44. alert('$content click');
  45. }
  46. document.body.onclick = function() {
  47. alert('body click');
  48. }
  49. </script>
  50. </body>
  51. </html>

在手机上运行上面代码,会发现弹出的内容依次是:’modal touchstart’ > ‘content click’ > ‘body click’。会发现,明明点击的是弹出层,为什么会触发内容和body的click事件呢?

移动端浏览器要判断用户是否有进一步的操作[双击],touchstartclick执行会有延迟300ms。所以在触发弹窗A的touchstart后,期间会有延迟才执行click事件,但弹窗已经隐藏不现实,从而在同样位置执行click操作后,其实是在 content 内容B上执行。

点透出现的场景

刚才举例说明了什么是点透,其实点透的出现场景可以总结如下:
1、A/B两个层上下z轴重叠。
2、上层的A点击后消失或移开。(这一点很重要)
3、B元素本身有默认click事件(如a标签) 或 B绑定了click事件。
在以上情况下,点击A/B重叠的部分,就会出现点透的现象。

解决方案

1、对于B元素本身没有默认click事件的情况(无a标签等),应统一使用touch事件。
2、对于B元素本身存在默认click事件的情况,应取消A元素的默认点击事件,从而阻止click事件的产生。即应在上例的$modal touchstart监听事件中添加代码如下:
e.preventDefault();
3、在zepto修复问题之前,有fastclick、hammer等通用库可以使用。
其中最常使用的还是fastclick,地址 :https://github.com/ftlabs/fastclick