美文网首页
vue实现弹框组件

vue实现弹框组件

作者: ZZES_ZCDC | 来源:发表于2020-05-02 14:56 被阅读0次

    效果

    问题总结

    添加到body

    this.$nextTick(() => {
      const body = document.querySelector('body')
      if (body.append) {
        body.append(this.$el)
      } else {
        body.appendChild(this.$el)
      }
    })
    

    禁止页面滚动

    if (this.show) {
      document.body.style.height = '100vh'
      document.body.style['overflow-y'] = 'hidden'
    } else {
      document.body.style.height = 'unset'
      document.body.style['overflow-y'] = 'auto'
    }
    

    切换页面或其他情况, 需要清除添加到body里的弹框

     destroyed () {
        // 如果被销毁, 则清除body里的dom
        if (this.appendBody && this.$el && this.$el.parentNode) {
          this.$el.parentNode.removeChild(this.$el)
        }
      }
    

    组件源码

    <template>
      <transition name="fade">
        <div class="b-popup" v-show="show">
          <transition name="b-fade">
            <div
              class="b-popup-mask"
              @click="close"
              v-show="hasMask && show">
            </div>
          </transition>
          <transition name="b-slide-up">
            <div
              v-show="show"
              class="b-popup-box b-slide-up"
              :class="contentPosition"
              :style="{background: popupBg, width: contentWidth, borderRadius: contentBorderRadius}">
              <div v-if="!noHeader" class="b-popup-header">
                <div class="iconfont icon-close" :class="closePosition" @click="close"></div>
                <div class="title">{{title}}</div>
              </div>
              <div class="b-popup-body">
                <slot name="body"></slot>
              </div>
            </div>
          </transition>
        </div>
      </transition>
    </template>
    <script>
    export default {
      name: 'BPopup',
      props: {
        open: {
          type: Boolean,
          default: false
        },
        title: {
          type: String,
          default: '标题'
        },
        closePosition: {
          type: String,
          default: 'right'
        },
        noHeader: {
          type: Boolean,
          default: false
        },
        appendBody: {
          type: Boolean,
          default: true
        },
        popupBg: {
          type: String,
          default: '#fff'
        },
        hasMask: {
          type: Boolean,
          default: true
        },
        contentPosition: {
          type: String,
          default: 'bottom' // bottom, center, top
        },
        contentWidth: {
          type: String,
          default: '100%'
        },
        contentBorderRadius: {
          type: String,
          default: 'unset'
        }
      },
      model: {
        prop: 'open',
        event: 'update'
      },
      mounted () {
        if (this.appendBody) {
          this.$nextTick(() => {
            const body = document.querySelector('body')
            if (body.append) {
              body.append(this.$el)
            } else {
              body.appendChild(this.$el)
            }
          })
        }
        this.show = this.open
      },
      destroyed () {
        // 如果被销毁, 则清除body里的dom
        if (this.appendBody && this.$el && this.$el.parentNode) {
          this.$el.parentNode.removeChild(this.$el)
        }
      },
      data () {
        return {
          show: false
        }
      },
      methods: {
        close () {
          this.show = false
          this.$emit('update', false)
        }
      },
      watch: {
        open () {
          this.show = this.open
        },
        show () {
          if (this.show) {
            document.body.style.height = '100vh'
            document.body.style['overflow-y'] = 'hidden'
          } else {
            document.body.style.height = 'unset'
            document.body.style['overflow-y'] = 'auto'
          }
        }
      }
    }
    </script>
    <style lang="scss" scoped>
    .b-popup {
      position: fixed;
      top: 0;
      bottom: 0;
      left: 0;
      right: 0;
      display: flex;
      flex-direction: column;
      justify-content: flex-end;
      z-index: 2;
      .b-popup-mask {
        position: fixed;
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;
        pointer-events: auto;
        background-color: rgba(37,38,45,.7);
      }
      .b-popup-box {
        position: absolute;
        width: 100%;
        max-width: 100%;
        max-height: 100%;
        overflow: auto;
        text-align: center;
        font-size: 57px;
        // background: #fff;
        z-index: 2;
        &.center {
          left: 50%;
          top: 50%;
          transform: translate(-50%, -50%);
        }
        &.top {
          top: 0;
        }
        .b-popup-header {
          padding: 70px 0;
          position: relative;
          border-bottom: 2px solid #e0e0e0;
        }
        .icon-close {
          position: absolute;
          font-size: 70px;
          color: #b8b8b8;
          &.right {
            right: 40px;
          }
          &.left {
            left: 40px;
          }
        }
      }
      .b-fade {
        &-enter, &-leave-to {
          opacity: 0;
        }
        &-enter-active, &-leave-active {
          transition: opacity 250ms;
        }
      }
      .b-slide-up {
        &-enter, &-leave-to {
          transform: translate3d(0, 100%, 0);
        }
        &-leave-active, &-enter-active {
          transition: transform 300ms cubic-bezier(0.165, 0.84, 0.44, 1);
        }
      }
    }
    
    .fade-enter-active, .fade-leave-active {
      transition: opacity .5s;
    }
    .fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
      opacity: 0;
    }
    </style>
    

    相关文章

      网友评论

          本文标题:vue实现弹框组件

          本文链接:https://www.haomeiwen.com/subject/zmukghtx.html