最近移动端m站的开发中遇到了点击穿透问题,就此总结一番。
先说下我遇到的问题,项目使用react框架,并且引入了react-fastclick库,可以解决click事件的穿透问题,但是对于下层是 a标签 的情况,依旧存在穿透问题,会触发链接。
我的解决方法是把上层的事件放在了一个setTimeout(() => {}, 0)
中。
goBack() {
setTimeout(() => {
browserHistory.goBack()
}, 0)
}
下面说一下点击穿透问题是怎么来的。
点击穿透是指,在移动端H5页面中,当点击事件会切到一个新页面时(比如返回上一页面,或弹出弹窗页面,或关闭遮罩层),新页面中相应的位置如果有事件(或input等输入框),就会被触发。
这是因为在pc页面中,一次点击行为包括 mousedown -> click -> mouseup
,而在移动端,则是touchstart -> touchmove -> touchend
。
在移动端,虽然没有 mouse,依然会响应 mouse 事件,但是有个300ms 的时延。于是移动端的一次点击其实是这样的:touchstart -> touchmove -> touchend -> 300ms ->mousedown -> click -> mouseup
。
之所以有时延,是因为在这 300ms 中,移动端会检测是否有双击行为。
正因如此,在这 300ms 之中,页面变成了新的页面,click 事件就会触发成新页面中的 click 事件了。
这种问题可以通过一些库来解决,比如fastclick库,其实现思路是,取消 click 事件(参看源码 164-173 行),用 touchend 模拟快速点击行为(参看源码 521-610 行)。其实就是在检测到 touchend 事件的时候,会通过 DOM 自定义事件立即出发模拟一个 click 事件,并把浏览器在 300ms 之后真正的 click 事件阻止掉。
但正如文章开头所讲,fastclick 对于 a 标签的情况依然存在问题,仍需自行解决。
对于浏览器点击事件更加详尽的介绍,可参考这篇文章,虽是远古文,耐心读下来对夯实基础会有很大的帮助。