如何解决移动端击穿(穿透)问题



在移动端开发的时候,我们有时候会遇到这样一个 bug:点击关闭遮罩层的时候,遮罩层下面的带有点击的元素也会被触发,给人一种击穿了页面的感觉,这是为什么呢?

  • 点击“打开弹框”按钮,显示遮罩层
  • 点击“关闭弹框”按钮,遮罩层消失,底下的连接被触发

事例 js 部分代码

var show = document.getElementById('show') // 打开按钮
var mask = document.getElementById('mask') // 遮罩层
var btn = document.getElementById('btn') // 关闭按钮

show.onclick = function () {
mask.style.display = 'block'
}

btn.addEventListener('touchstart', function () {
mask.style.display = 'none'
}, false)
  • 这样问题的形成原因是什么呢?
  • 我们先来看一段代码:(以下代码需在移动端上运行)
<div id="btn">我是一个按钮</div>
var btn = document.getElementById('btn')
btn.addEventListener('touchstart', function () {
console.log('start')
}, false)

btn.addEventListener('touchmove', function () {
console.log('move')
}, false)

btn.addEventListener('touchend', function () {
console.log('touchend')
}, false)

btn.addEventListener('click', function () {
console.log('click')
}, false)

以上代码会出现 2 种运行情况

start ===> move ===> end
start ===> end ===> click

看到这里相信大家都明白了,由于「关闭弹框」按钮绑定的事件是touch,a 标签是click事件,在touch事件触发后,我们弹出框的遮罩层就消失了,这时候的click事件就被 a 标签给捕获到了,形成了击穿的效果

方法一、阻止默认事件

btn.addEventListener('touchend', function (e) {
mask.style.display = 'none'
e.preventDefault()
}, false)

在执行 touchstart 和 touchend 事件时,隐藏执行完隐藏命令后,立即阻止后续事件(推荐在 touchend 时,阻止后续的默认事件)

方法二、统一使用 click 事件

btn.addEventListener('click', function () {
mask.style.display = 'none'
}, false)

这个方法简单,就是交互的效率没有click事件高,另外,用户在touch的时候,有可能微微滑动了一下,就会无法触发点击事件。影响用户体验。

方法三、延迟执行

btn.addEventListener('touchend', function () {
setTimeout(function () {
mask.style.display = 'none' // 可以使用fadeOut动画
}, 300)
}, false)

点击之后,我们不立即隐藏。让遮罩在 350ms 毫秒内淡出消失。(我为了演示方便就没有添加动画了,采用了定时器方法。)

方法四、 css 属性 pointer-events

click.setAttribute('style', 'pointer-events:none')
mask.style.display = 'none'
setTimeout(function () {
click.setAttribute('style', 'pointer-events:auto')
}, 350)

这样做法是,在遮罩消失之前,先让 a 标签忽略点击事件,这样遮罩层的点击事件,就不会被 a 标签捕获到。还是等 350 毫秒之后,再次赋予 a 标签的点击能力。这个方法跟方法三原理相似,只是利用了不同的 css 属性而已。个人觉得方法三比较好一点。方法四有明显的 2 个缺点:

  • 遮罩层下面可能有多个带有事件的元素,那么你需要给所有可点击元素添加pointer-events属性 然后删除。不仅容易出错,还影响性能
  • 如果用户在350毫秒内点击了元素,会造成页面失效的错觉,影响体验。

方法五、fastClick 库

这个库的引用方法,在我上一篇文章中已经讲到。fastClick 的原理就是使用了方法一的做法。fastClick 在 touchend 阶段 调用 event.preventDefault,然后通过 document.createEvent 创建一个 MouseEvents,然后 通过 eventTarget.dispatchEvent 触发对应目标元素上绑定的 click 事件



原文始发于微信公众号(消失的程序员):如何解决移动端击穿(穿透)问题

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/250682.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!