移动端 弹窗-内容可滚动,背景不动

实际开发中,总免不了使用弹窗,如果弹窗比较短,内容不需要滑动,那还好处理,vue中直接阻止滑动就可以了,但是如果弹窗内的内容需要滑动,那就有点麻烦了,之前看到的方案都是给body设置fixed,但是事实上都不是很好,还好,网上找了一种解决方案,实现思路比较简单直接,滑动的时候监听touch事件,通过target来判断滑动的是谁,如果是遮罩层,那么直接preventDefault(),当然,这还没完,还需要处理滑动的边界情况,在最顶部以及最底部,此时,如果继续滑动的话,底部的内容依然会滑动,所以,在边界情况下还是需要阻止滑动,下面以自己实现的mask组件为例来说明把,其实这基本就实现了需求

话不多说,下面附上自己写的一个通用组件

<template>
  <div class="lo-mask" @touchstart="start" @touchmove="move" @touchend="end">
    <div class="mask-container" ref="container">
      <p v-for="val in 20">{{val}}</p>
      <div class="content">
        <slot name="title"></slot>
        <slot name="content"></slot>
      </div>
      <footer>
        <button v-if="cancel"  @click="cancelBtn" class="btn cancel">{{cancel}}</button>
        <span class="line" v-if="cancel&&confirm"></span>
        <button  v-if="confirm"  @click="successBtn" class="btn">{{confirm}}</button>
      </footer>
    </div>
  </div>

</template>

<script>
  export default {
    name: 'loMask',
    props: {
      cancel: {
        type: String,
        default: ''
      },
      confirm: {
        type: String,
        default: ''
      }
    },
    data() {
      return {
        startY: 0
      }
    },
    methods: {
      successBtn() {},
      cancelBtn() {},

      start(e) {
        // console.log(e.target);
        // let target = e.target;
        // console.log(target.className);
        console.log(e);
        this.startY = e.touches[0].clientY;
      },
      move(e) {
        // console.log(e.target);
        // e.preventDefault()
        let container = this.$refs.container;
        let target = e.target;

        let sTop = container.scrollTop,       // 滚动的高度    (滚动卷去的高度)
            sHeight = container.scrollHeight, // 可滚动的高度  (实际总高度)
            vHeight = container.offsetHeight; // 视窗的高度    (可视区域高度)
        if (target.className === 'lo-mask') {
          e.preventDefault()
        }
        let newY = e.touches[0].clientY;
        let dis = newY - this.startY;

        if (dis > 0) {
          // 向下
          if (sTop <= 0&& e.cancelable) {
            e.preventDefault()
          }
        } else {
          // 向上
          if (sTop + vHeight >= sHeight&& e.cancelable) {
            e.preventDefault()
          }
        }

        // 还得检测是否滑动到顶或者到底了
        // console.log(container);
        // console.log(container.scrollTop);    // 滚动的高度
        // console.log(container.offsetHeight); // 视窗的高度
        // console.log(container.scrollHeight); // 可滚动的高度
        // 区分上下滑动

      },
      end() {}
    }
  }
</script>

<style scoped lang="scss">
  .lo-mask{
    position: fixed;
    width: 100%;
    height: 100%;
    background:rgba(0, 0, 0, 0.7);
    z-index: 50;
    top: 0;
    left: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding-left: 0.2rem;
    padding-right: 0.2rem;
    overflow: auto;
  }
  .mask-container{
    position: relative;
    display: flex;
    flex-direction: column;
    width: 2.7rem;
    min-height: 1.5rem;
    max-height: 2rem;
    overflow-y: scroll;
    background-color: #fff;
    border-radius: 0.08rem;
    box-shadow: 0 3px 19px rgba(89, 89, 89, 0.85);
  }
  .content{
    flex: 1;
  }
  footer{
    display: flex;
    box-sizing: content-box;
    align-items: center;
    justify-content: space-around;
    width: 100%;
    height: 0.4rem;
    background-color: #f7f7f7;
    border-top: 1px solid #E2E2E2;
    border-radius: 0 0 0.08rem 0.08rem;
    .btn{
      flex: 1;
      height: 0.4rem;
      color: #E9327B;
      font-size: 0.17rem;
      font-weight: bold;
    }
    .line{
      width: 1px;
      height: 0.4rem;
      background-color: #E2E2E2;
    }
  }

</style>

直接复制过去就可以用,还是不错的

猜你喜欢

转载自www.cnblogs.com/ysla/p/11992345.html