阅读 4754

解决移动端滚动穿透

前言

之前一直做PC系统,目前做移动端也遇到一些问题,本文解决移动端滚动的糟心问题!

全局滚动

全局滚动即滚动是在body上的滚动。如果只有一个全局滚动是没有问题的,问题在于全局滚动的页面出现了弹窗 如下图所示情景:

在此情况下的弹窗会出现如下问题:

滚动穿透--固定弹窗

啥意思呢,就是在弹窗点击或滑动的时候,底层的全局滚动也会跟着滑动!!! 刚出现问题的时候也在网上查找了一波,尝试了如下方法:

  1. 弹窗时给body设置overflow:hidden;(缺点:ios没用)
  2. 弹窗时给body设置position:fixed;(缺点:滚动位置会丢失,ios没用)

针对此情景的完美解决方法是:

给弹窗加上@touchmove.stop.prevent,即可阻止touchmove事件传递到body,也就解决了滚动穿透

滚动穿透——滚动弹窗

还是这张图,情况就是弹窗里也是有滚动的!!!如果使用了@touchmove.stop.prevent,那的确可以解决滚动穿透的问题,但是由于阻止了@touchmove,自身也无法滚动了,不信自己写demo试试~

那针对此种情况完美解决方案是: 在弹窗打开的时候给body的全局滚动设置position:fixed属性,并设置top值;由于设置了fixed属性,那在弹窗的时候body就没有滚动条了。此时如果这么设置会发现body虽然没有了滚动穿透,但是原来的位置丢失了。所以再给body设置fixed属性的时候,要把当前的滚动位置赋值给css的top属性,那在视觉上就没有任何变化了。

      fixedBody () {
        let scrollTop = document.body.scrollTop || document.documentElement.scrollTop
        document.body.style.cssText += 'position:fixed;width:100%;top:-' + scrollTop + 'px;'
      }
复制代码

那在弹窗关闭的时候如何处理呢? 弹窗关闭的时候则要清除fixed固定定位和top值;并设置其滚动位置位置top值,则又恢复了滚动功能,而且视觉上没有任何变化,是目前最完美的解决方案!

      looseBody () {
        let body = document.body
        body.style.position = ''
        let top = body.style.top
        document.body.scrollTop = document.documentElement.scrollTop = -parseInt(top)
        body.style.top = ''
      }
复制代码

总结

以上两种方案解决了固定弹窗和滚动弹窗对于body全局滚动的影响。文章末尾在针对vue做一个自定义指令封装

局部滚动

局部滚动,还是刚才的图片,在弹窗里的滚动,在Android上滚动没啥问题,但是在ios局部滚动有时就会实现。

复现步骤:

  • ①从滚动区域外从上往下化
  • ②在滑动滚动区域,发现滚动竟然失效了!!!活见鬼了....这TM还是原生属性。多重发几次,一定可以复现的。

解决办法: 使用插件better-scroll,大家伙自己研究文档就行。

vue封装

vue:

    directives: {
      fixed: {
        // inserted 被绑定元素插入父节点时调用
        inserted () {
          let scrollTop = document.body.scrollTop || document.documentElement.scrollTop
          document.body.style.cssText += 'position:fixed;width:100%;top:-' + scrollTop + 'px;'
        },
        // unbind 指令与元素解绑时调用
        unbind () {
          let body = document.body
          body.style.position = ''
          let top = body.style.top
          document.body.scrollTop = document.documentElement.scrollTop = -parseInt(top)
          body.style.top = ''
        }
      }
    },
复制代码

自定义指令使用 html:

<div  v-if="isShowRecordModal" v-fixed>
    ....
    ....
</div>
复制代码

该指令的注意点是必须使用v-if开启关闭弹窗,因为该指令依赖于dom的插入和注销,使用v-show是肯定不行的。

结语

种一棵树最好的时间是十年前,其次是现在。

如果有帮助请点赞哟~

关注下面的标签,发现更多相似文章
评论