点击穿透问题、蒙版下的内容滚动问题

移动端 touch 和 click 区别

移动端点击后依次触发:touchstart => touchmove => touchend => click
其中触碰后未移动或移动距离很小,则会在触碰结束后触发click事件,但click事件会有300ms延迟(这是为了等待用户手势操作,例如缩放、滑动等,如果通过preventDefaulttouch-action: none;等禁用了触控相关的浏览器默认行为,则不会触发后续方法)。


点击穿透问题

由于click事件延迟300ms触发,在该期间内如果页面发生变化,原本触发touch事件的元素所在位置已被其他元素代替,则由该新元素触发click事件。

  1. 等待300ms后再移除上层元素
  2. 300ms期间临时禁止下层元素的点击事件,如添加pointer-events: none;等。
  3. 阻止后续的click事件发生
    • Fastclick.js 插件
      它会在检测到touchend事件时通过 DOM 自定义事件立即触发一个模拟click事件,并把浏览器在 300 毫秒之后真正触发的click事件阻止掉
    • 使用touch-action: none;禁用浏览器对touch事件的默认响应。
    • touchstart事件回调中使用preventDefault,但在部分浏览器中该方式可能无效。

蒙版下的内容滚动问题

操作弹窗时,蒙版下的父级元素也会被滚动

  1. 打开蒙层时,给滚动元素的父级添加样式,关闭蒙层时,移除样式:
overflow: hidden;
height: 100%;

缺点:滚动条消失可能会导致页面跳动。

  1. 移动端可以给蒙层dom节点的touchmove添加preventDefault阻止页面滚动的默认行为:
node.addEventListener('touchmove', e => {
  e.preventDefault()
}, false)

缺点:会导致弹窗内容也无法滚动,只适用于弹窗内容无需滚动的场景。

  1. 最终方案 : 既然我们要阻止页面滚动,那么何不将其固定在视窗(即position: fixed),这样它就无法滚动了,当蒙层关闭时再释放。
    当然还有一些细节要考虑,将页面固定视窗后,内容会回头最顶端,这里我们需要记录一下,同步top值。

示例代码:

        var bodyEl = document.getElementById('toFix');
        var top = 0;
        function stopBodyScroll(isFixed) {
            if (isFixed) {
                top = window.scrollY;
                bodyEl.style.position = 'fixed';
                bodyEl.style.top = -top + 'px';
            } else {
                bodyEl.style.position = '';
                bodyEl.style.top = '';
                window.scrollTo(0, top) // 回到原先的top
            }
        }


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容