queenwuli
2020-12-15 3522317ba504a84199e185437b4ba66dbb4baf85
hive-app/components/uni-popup/uni-popup.vue
New file
@@ -0,0 +1,294 @@
<template>
   <view v-if="showPopup" class="uni-popup" :class="[popupstyle]" @touchmove.stop.prevent="clear">
      <uni-transition v-if="maskShow" :mode-class="['fade']" :styles="maskClass" :duration="duration" :show="showTrans"
       @click="onTap" />
      <uni-transition :mode-class="ani" :styles="transClass" :duration="duration" :show="showTrans" @click="onTap">
         <view class="uni-popup__wrapper-box" @click.stop="clear">
            <slot />
         </view>
      </uni-transition>
   </view>
</template>
<script>
   import uniTransition from '../uni-transition/uni-transition.vue'
   import popup from './popup.js'
   /**
    * PopUp 弹出层
    * @description 弹出层组件,为了解决遮罩弹层的问题
    * @tutorial https://ext.dcloud.net.cn/plugin?id=329
    * @property {String} type = [top|center|bottom] 弹出方式
    *    @value top 顶部弹出
    *    @value center 中间弹出
    *    @value bottom 底部弹出
    *    @value message 消息提示
    *    @value dialog 对话框
    *    @value share 底部分享示例
    * @property {Boolean} animation = [ture|false] 是否开启动画
    * @property {Boolean} maskClick = [ture|false] 蒙版点击是否关闭弹窗
    * @event {Function} change 打开关闭弹窗触发,e={show: false}
    */
   export default {
      name: 'UniPopup',
      components: {
         uniTransition
      },
      props: {
         // 开启动画
         animation: {
            type: Boolean,
            default: true
         },
         // 弹出层类型,可选值,top: 顶部弹出层;bottom:底部弹出层;center:全屏弹出层
         // message: 消息提示 ; dialog : 对话框
         type: {
            type: String,
            default: 'center'
         },
         // maskClick
         maskClick: {
            type: Boolean,
            default: true
         }
      },
      provide() {
         return {
            popup: this
         }
      },
      mixins: [popup],
      watch: {
         /**
          * 监听type类型
          */
         type: {
            handler: function(newVal) {
               this[this.config[newVal]]()
            },
            immediate: true
         },
         /**
          * 监听遮罩是否可点击
          * @param {Object} val
          */
         maskClick(val) {
            this.mkclick = val
         }
      },
      data() {
         return {
            duration: 300,
            ani: [],
            showPopup: false,
            showTrans: false,
            maskClass: {
               'position': 'fixed',
               'bottom': 0,
               'top': 0,
               'left': 0,
               'right': 0,
               'backgroundColor': 'rgba(0, 0, 0, 0.4)'
            },
            transClass: {
               'position': 'fixed',
               'left': 0,
               'right': 0,
            },
            maskShow: true,
            mkclick: true,
            popupstyle: 'top'
         }
      },
      created() {
         this.mkclick = this.maskClick
         if (this.animation) {
            this.duration = 300
         } else {
            this.duration = 0
         }
      },
      methods: {
         clear(e) {
            // TODO nvue 取消冒泡
            e.stopPropagation()
         },
         open() {
            this.showPopup = true
            this.$nextTick(() => {
               new Promise(resolve => {
                  clearTimeout(this.timer)
                  this.timer = setTimeout(() => {
                     this.showTrans = true
                     // fixed by mehaotian 兼容 app 端
                     this.$nextTick(() => {
                        resolve();
                     })
                  }, 50);
               }).then(res => {
                  // 自定义打开事件
                  clearTimeout(this.msgtimer)
                  this.msgtimer = setTimeout(() => {
                     this.customOpen && this.customOpen()
                  }, 100)
                  this.$emit('change', {
                     show: true,
                     type: this.type
                  })
               })
            })
         },
         close(type) {
            this.showTrans = false
            this.$nextTick(() => {
               this.$emit('change', {
                  show: false,
                  type: this.type
               })
               clearTimeout(this.timer)
               // 自定义关闭事件
               this.customOpen && this.customClose()
               this.timer = setTimeout(() => {
                  this.showPopup = false
               }, 300)
            })
         },
         onTap() {
            if (!this.mkclick) return
            this.close()
         },
         /**
          * 顶部弹出样式处理
          */
         top() {
            this.popupstyle = 'top'
            this.ani = ['slide-top']
            this.transClass = {
               'position': 'fixed',
               'left': 0,
               'right': 0,
            }
         },
         /**
          * 底部弹出样式处理
          */
         bottom() {
            this.popupstyle = 'bottom'
            this.ani = ['slide-bottom']
            this.transClass = {
               'position': 'fixed',
               'left': 0,
               'right': 0,
               'bottom': 0
            }
         },
         /**
          * 中间弹出样式处理
          */
         center() {
            this.popupstyle = 'center'
            this.ani = ['zoom-out', 'fade']
            this.transClass = {
               'position': 'fixed',
               /* #ifndef APP-NVUE */
               'display': 'flex',
               'flexDirection': 'column',
               /* #endif */
               'bottom': 0,
               'left': 0,
               'right': 0,
               'top': 0,
               'justifyContent': 'center',
               'alignItems': 'center'
            }
         }
      }
   }
</script>
<style lang="scss" scoped>
   .uni-popup {
      position: fixed;
      /* #ifndef APP-NVUE */
      z-index: 99;
      /* #endif */
   }
   .uni-popup__mask {
      position: absolute;
      top: 0;
      bottom: 0;
      left: 0;
      right: 0;
      background-color: $uni-bg-color-mask;
      opacity: 0;
   }
   .mask-ani {
      transition-property: opacity;
      transition-duration: 0.2s;
   }
   .uni-top-mask {
      opacity: 1;
   }
   .uni-bottom-mask {
      opacity: 1;
   }
   .uni-center-mask {
      opacity: 1;
   }
   .uni-popup__wrapper {
      /* #ifndef APP-NVUE */
      display: block;
      /* #endif */
      position: absolute;
   }
   .top {
      /* #ifdef H5 */
      top: var(--window-top);
      /* #endif */
      /* #ifndef H5 */
      top: 0;
      /* #endif */
   }
   .bottom {
      bottom: 0;
   }
   .uni-popup__wrapper-box {
      /* #ifndef APP-NVUE */
      display: block;
      /* #endif */
      position: relative;
      /* iphonex 等安全区设置,底部安全区适配 */
      /* #ifndef APP-NVUE */
      padding-bottom: constant(safe-area-inset-bottom);
      padding-bottom: env(safe-area-inset-bottom);
      /* #endif */
   }
   .content-ani {
      // transition: transform 0.3s;
      transition-property: transform, opacity;
      transition-duration: 0.2s;
   }
   .uni-top-content {
      transform: translateY(0);
   }
   .uni-bottom-content {
      transform: translateY(0);
   }
   .uni-center-content {
      transform: scale(1);
      opacity: 1;
   }
</style>