移动端阻止弹窗下层页面被滑动方法介绍

简介: 移动端阻止弹窗下层页面被滑动方法介绍

移动端阻止弹窗下层页面被滑动方法介绍


在做H5开发时,很多场景下都需要弹窗


当出现弹窗时,大部分场景下是期望弹窗下层页面不能被滑动的


当然也不期望弹窗被滑动


近期肝页面又碰到了这个问题


下面介绍几种最常用的方式,以及一些边界情况与应对策略


overflow:hidden


流传最广的方式就是 给元素设置 overflow:hidden

body设置,就能达到阻止页面滑动的目的


document.body.style.overflow = 'hidden'
document.body.style.overflow = 'visible'


大部分情况下这个是能有效果的


但在部分机器上,这个是不生效的:


弹窗遮罩


还有一种情况如下,页面部分元素有局部滑动


<body style="overflow:hidden;">
  <div style="overflow:scroll;height:100%;">
    <!-- more element -->
  </div>
</body>


当前情况给body设置 overflow:hidden依旧是无效果的


此时给弹窗加上遮罩如下,正常情况下,下层元素就不会收到touchmove事件


<body style="overflow:hidden;">
  <div style="overflow:scroll;height:100%;">
    <!-- more element -->
  </div>
  <!-- dialog -->
  <div class="dialog">
    <!-- 遮罩 -->
    <div class="mask" style="position:fixed;inset:0;"></div>
    <div class="content"></div>
  </div>
</body>


其中inset属性是left,top,right,bottom的简写


但在部分机型下,下层元素仍然会收到touchmove事件,因此会跟着滑动

于是需要祭出下面的方法


prevent touchmove


阻止触摸滑动事件touchmove的默认行为


const touchHandle = function(e) {
  e.preventDefault()
}
// 弹窗的事件
{
  onShow(){
    document.body.addEventListener('touchmove', preventDefault, {
      passive: false,
    });
  },
  onHide(){
    document.body.removeEventListener('touchmove', preventDefault);
  }
}


在弹窗打开时直接阻止目标元素的滑动事件的默认行为

弹窗内容是不可滑动的话,那么这种方法是最省事高效的

如果弹窗中有可滑动的内容,且滑动的内容比较复杂

那么通过touchmove去细力度的控制阻止滑动事件时就很麻烦


position:fixed


还有一种常用的就是position:fixed


在弹窗打开时,将目标元素进行固定,在关闭时恢复


由于定位会改变元素在页面上的位置,所以需要再fixed前记录元素的位置

取消fixed之后将元素又滚动到原来的位置


// 弹窗的事件
{
  onShow(){
    document.body.style.top = `${
      document.body.getClientRects()[0].top
    }px`;
    document.body.style.position = 'fixed';
    document.body.style.left = '0';
    document.body.style.right = '0';
  },
  onHide(){
    document.body.style.position = 'visible';
    window.scrollTo(
      0,
      Math.abs(+document.body.style.top.replace('px', ''))
    );
  }
}


使用class代替style


这个也是碰巧发现的,在iOS低端机将上述方式都尝试后


仍发现一个问题,现象如下(TODO:补图)


下层页面不会被滑动了,但遮罩和弹窗整体还能被下拉


弹窗是一个下拉列表弹窗,其出现的位置需要动态的计算,如下结构


<body style="overflow:hidden;">
  <!-- dialog -->
  <div class="dialog" style="top:88px;">
    <!-- 遮罩 -->
    <div class="mask" style="position:fixed;inset:0;"></div>
    <!-- 内容 -->
    <div class="content"></div>
  </div>
</body>


最终发现是由于styleclass设置的样式在这个机型上展示虽然一致

但实际交互起来的表现却不一致


修复后的html结构如下,在元素里插入了一个style标签,使用class选择器与!important重载这个距离的样式


<body style="overflow:hidden;">
  <!-- dialog -->
  <div class="dialog" style="top:88px;">
    <!-- 遮罩 -->
    <div class="mask" style="position:fixed;inset:0;"></div>
    <!-- 内容 -->
    <div class="content"></div>
    <style>
      .dialog{
        top:88px !important;
      }
    </style>
  </div>
</body>


代码如下


{
  onShow(){
    setTimeout(() => {
      const dialogEl = document.querySelector<HTMLElement>('.dialog')
      if (!dialogEl) {
        return
      }
      const style = document.createElement('style')
      style.textContent = `
      .dialog{
        top:${dialogEl.style.top} !important;
      }
      `
      dialogEl.append(style)
    }, 200)
  }
}


非常令人迷惑的一个操作,但就是解决了问题


小结


针对移动端弹窗下层页面可被滑动的异常场景


本文介绍了4种常见解决方法,与1种"谜之操作"


demo演示


网络异常,图片无法展示
|



  • PC扫码体验


相关文章
|
运维 监控 前端开发
前端监控究竟有多重要
前端监控究竟有多重要
421 0
uniapp根据官方文档上传图片的方法
uniapp根据官方文档上传图片的方法
|
9月前
|
缓存 Java 测试技术
【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
1072 3
【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
|
前端开发 JavaScript
react-qr-code的第三方库来将URL转换成二维码图片
在React中,你可以使用一个叫做react-qr-code的第三方库来将URL转换成二维码图片并保存。首先,你需要安装这个库: ``` npm install react-qr-code ``` 然后,在你的组件中引入react-qr-code: ``` import QRCode from 'react-qr-code'; ``` 接着,在render方法中使用QRCode组件,将URL作为一个属性传递进去: ``` render() { const url = 'https://www.example.com'; return ( <div> <Q
1290 0
|
JavaScript 定位技术
【天地图】vue 天地图 T is not defined
【天地图】vue 天地图 T is not defined
453 1
|
JavaScript 前端开发
Web Components详解-Shadow DOM样式控制
Web Components详解-Shadow DOM样式控制
340 3
|
Oracle 关系型数据库 MySQL
【实操记录】MySQL二进制安装包部署
本文详细描述了采用二进制安装的各个步骤,具有较强的参考意义,基本可作为标准步骤实施
679 0
|
安全 算法 数据建模
阿里云SSL证书价格从免费到收费详细收费价格表
阿里云SSL证书价格一年多少钱?阿里云SSL证书分为收费和免费两种,免费SSL为DV单域名证书,收费SSL证书类型分为DV域名和OV企业型,证书品牌分为Digicert、Rapid、Globalsign、Wosign和vTrus,SSL证书类型不同、品牌不同、域名类型不同价格也不同
12766 1
阿里云SSL证书价格从免费到收费详细收费价格表
|
JavaScript Java Android开发
android studio中文乱码各种情况的解决办法
android studio中文乱码各种情况的解决办法
729 0
android studio中文乱码各种情况的解决办法
|
JavaScript 前端开发 API
Vue.js 深度解析:nextTick 原理与应用
Vue.js 深度解析:nextTick 原理与应用