1、前置知识 - 事件触发顺序

PC网页上的大部分操作都是用鼠标的,即响应的是鼠标事件,包括mousedown、mouseup、mousemove和click事件。一次点击行为,可被拆解成:mousedown -> mouseup -> click 三步。

在手机上没有鼠标,所以就用触摸事件去实现类似的功能。touch事件包含touchstart、touchmove、touchend,注意手机上并没有tap事件。手指触发触摸事件的过程为:touchstart -> touchmove -> touchend。虽然手机上没有鼠标,但不代表手机不能响应mouse事件(其实是借助touch去触发mouse事件)。也就是说在移动端的click事件可以拆解为:touchstart -> touchmove -> touchend -> click。

注意浏览器在 touchend 之后会等待约 300ms ,如果没有 tap 行为,则触发 click 事件。 而浏览器等待约 300ms 的原因是,判断用户是否是双击(double tap)行为,双击过程中就不适合触发 click 事件了。 由此可以看出 click 事件触发代表一轮触摸事件的结束。

2、什么是点击穿透问题

定义:在触发完touchstart事件的时候紧接着触发他父级元素的click事件

具体的表现形式有以下三种: (1)当前页面点击穿透:点击蒙层(mask)上的关闭按钮,蒙层消失后发现触发了按钮下面元素的click事件, 蒙层的关闭按钮绑定的是touch事件,而按钮下面元素绑定的是click事件,在touch事件触发之后,蒙层消失了,300ms后这个点的click事件fire,event的target自然就是按钮下面的元素,因为按钮跟蒙层一起消失了。

(2)跨页面点击穿透问题:如果按钮下面恰好是一个有href属性的a标签,那么页面就会发生跳转,因为a标签跳转默认是click事件触发,所以原理和上面的完全相同。

(3)另一种跨页面点击穿透问题:这次没有mask了,直接点击页内按钮跳转至新页,然后发现新页面中对应位置元素的click事件被触发了,和蒙层的道理一样,js控制页面跳转的逻辑如果是绑定在touch事件上的,而且新页面中对应位置的元素绑定的是click事件,而且页面在300ms内完成了跳转,三个条件同时满足,就出现这种情况了。

3、如何解决?

  • 方法1:使用e.preventDefault();阻止默认行为(但是不是所有的浏览器都支持)
  • 方法2:不要混用touch和click => 既然touch之后300ms会触发click,只用touch或者只用click就自然不会存在问题了