滚动穿透处理方案


之前看到过一些关于滚动穿透和点击穿透的文章,一般滚动穿透会比较常见,但是点击穿透却不怎么常见。之前的产品也没有要求过处理滚动穿透,所以也就没怎么处理过。

先说下业务场景:当前浏览的页面很长,是可以滚动的。页面上会出现弹框,弹框还可以滚动,这个时候就会有滚动穿透的问题了。

网上找到了一个思路特别简单的方法:弹窗打开的时候,给body设置 position: fixed;width: 100%;top: 0px;,让body脱离文档流,这个时候页面就不能滚动,按时弹窗还是可以滚动的。等弹窗关闭的时候,再把body设置恢复就行了。

贴上一个demo:如下。由于页面中遇到了3,4个遮罩层。所以就没有给每个click去添加,而且监测遮罩层的打开关闭——即变量layerShow。layerShow等于true即遮罩被打开的时候,获取dom的scrollTop,然后设置body的样式为position: fixed;width: 100%;top: ${-this.sctop}px;。当layerShow等于false即遮罩被关闭的时候,设置body样式恢复原状,然后让页面滚动到原来的位置window.scrollTo(0, this.sctop)

<template>
  <div id="blackbox" v-show="layerShow" class="layer">
    <div @click="closeLayer" class="layer-bg"></div>
    <div class="slot-wrapper">
      <slot></slot>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      sctop: 0
    };
  },
  props: {
    layerShow: {
      type: Boolean,
      default: false
    }
  },
  watch: {
    layerShowValue(newValue, oldValue) {
      if(newValue) {
        this.sctop = document.body.scrollTop || document.documentElement.scrollTop
        document.body.style.cssText = `position: fixed;width: 100%;top: ${-this
          .sctop}px;`;
      } else {
        document.body.style.cssText = "";
        window.scrollTo(0, this.sctop);
      }
    }
  },
  computed: {
    layerShowValue() {
      return this.layerShow;
    }
  },
  methods: {
    closeLayer() {
      this.$emit("closeLayer");
    }
  }
};
</script>

<style lang='scss' scoped>
.layer {
  position: fixed;
  top: 0;
  left: 0;
  width: 750px;
  height: 100vh;
  .layer-bg {
    background: #000;
    opacity: 0.5;
    width: 100%;
    height: 100%;
  }
  .slot-wrapper {
    position: absolute;
    top: 0;
    left: 0;
  }
}
</style>