<template> 
 | 
  <view 
 | 
    v-if="visibleSync" 
 | 
    class="tn-tips-class tn-tips" 
 | 
    :class="[tipsClass]" 
 | 
    :style="[tipsStyle]" 
 | 
  > 
 | 
    <view 
 | 
      class="tn-tips__content" 
 | 
      :class="[ 
 | 
        backgroundColorClass, 
 | 
        fontColorClass 
 | 
      ]" 
 | 
      :style="{ 
 | 
        backgroundColor: backgroundColorStyle, 
 | 
        color: fontColorStyle 
 | 
      }" 
 | 
    >{{ msg }}</view> 
 | 
  </view> 
 | 
</template> 
 | 
  
 | 
<script> 
 | 
   
 | 
  export default { 
 | 
    name: 'tn-tips', 
 | 
    props: { 
 | 
      // 层级 
 | 
      zIndex: { 
 | 
        type: Number, 
 | 
        default: 0 
 | 
      }, 
 | 
      // 提示框显示位置 top center bottom 
 | 
      position: { 
 | 
        type: String, 
 | 
        default: 'top' 
 | 
      }, 
 | 
      // 当位置设置为top的时候,设置距离顶部的距离 
 | 
      top: { 
 | 
        type: Number, 
 | 
        default: 0 
 | 
      } 
 | 
    }, 
 | 
    computed: { 
 | 
      tipsClass() { 
 | 
        let clazz = '' 
 | 
        switch (this.position) { 
 | 
          case 'top': 
 | 
            clazz += ' tn-tips--top' 
 | 
            break 
 | 
          case 'center': 
 | 
            clazz += ' tn-tips--center' 
 | 
            break 
 | 
          case 'bottom': 
 | 
            clazz += ' tn-tips--bottom' 
 | 
            break 
 | 
          default: 
 | 
            clazz += ' tn-tips--top' 
 | 
        } 
 | 
        if (this.showTips) { 
 | 
          clazz += ' tn-tips--show' 
 | 
        } 
 | 
         
 | 
        return clazz 
 | 
      }, 
 | 
      tipsStyle() { 
 | 
        let style = {} 
 | 
        if ((this.position === 'top' || this.position === '') && this.top) { 
 | 
          style.top = this.top + 'px' 
 | 
        } 
 | 
        style.zIndex = (this.zIndex ? this.zIndex : this.$t.zIndex.tips) + 1 
 | 
         
 | 
        return style 
 | 
      }, 
 | 
      backgroundColorStyle() { 
 | 
        return this.$t.color.getBackgroundColorStyle(this.backgroundColor) 
 | 
      }, 
 | 
      backgroundColorClass() { 
 | 
        return this.$t.color.getBackgroundColorInternalClass(this.backgroundColor) 
 | 
      }, 
 | 
      fontColorStyle() { 
 | 
        return this.$t.color.getFontColorStyle(this.fontColor) 
 | 
      }, 
 | 
      fontColorClass() { 
 | 
        return this.$t.color.getFontColorInternalClass(this.fontColor) 
 | 
      }, 
 | 
    }, 
 | 
    data() { 
 | 
      return { 
 | 
        //关闭提示框定时器 
 | 
        timer: null, 
 | 
        // 是否渲染组件 
 | 
        visibleSync: false, 
 | 
        // 是否显示内容 
 | 
        showTips: false, 
 | 
        // 提示信息 
 | 
        msg: '', 
 | 
        // 背景颜色 
 | 
        backgroundColor: '', 
 | 
        // 字体颜色 
 | 
        fontColor: '' 
 | 
      } 
 | 
    }, 
 | 
    methods: { 
 | 
      show(options = {}) { 
 | 
        const { 
 | 
          duration = 2000, 
 | 
          msg = '', 
 | 
          backgroundColor = '', 
 | 
          fontColor = '' 
 | 
        } = options 
 | 
         
 | 
        if (this.timer !== null) clearTimeout(this.timer) 
 | 
         
 | 
        // 如果没有设置内容则不弹出 
 | 
        if (!msg) { 
 | 
          this._clearOptions() 
 | 
          this.$emit('close') 
 | 
          return 
 | 
        } 
 | 
         
 | 
        this.msg = msg 
 | 
        this.backgroundColor = backgroundColor || '#01BEFF' 
 | 
        this.fontColor = fontColor || '#FFFFFF' 
 | 
         
 | 
        this.change('visibleSync', 'showTips', true) 
 | 
         
 | 
        this.timer = setTimeout(() => { 
 | 
          clearTimeout(this.timer) 
 | 
          this.timer = null 
 | 
          this.change('showTips', 'visibleSync', false) 
 | 
        }, duration) 
 | 
      }, 
 | 
       
 | 
      // 关闭时先通过动画隐藏弹窗和遮罩,再移除整个组件 
 | 
      // 打开时,先渲染组件,延时一定时间再让遮罩和弹窗的动画起作用 
 | 
      change(param1, param2, status) { 
 | 
        this[param1] = status 
 | 
        if (status) { 
 | 
          // #ifdef H5 || MP 
 | 
          this.timer = setTimeout(() => { 
 | 
            this[param2] = status 
 | 
            this.$emit(status ? 'open' : 'close') 
 | 
          }, 50) 
 | 
          // #endif 
 | 
          // #ifndef H5 || MP 
 | 
          this.$nextTick(() => { 
 | 
            this[param2] = status 
 | 
            this.$emit(status ? 'open' : 'close') 
 | 
          }) 
 | 
          // #endif 
 | 
        } else { 
 | 
          this.timer = setTimeout(() => { 
 | 
            this[param2] = status 
 | 
            this.$emit(status ? 'open' : 'close') 
 | 
            this._clearOptions() 
 | 
          }, 300) 
 | 
        } 
 | 
      }, 
 | 
       
 | 
      // 清除传递的参数 
 | 
      _clearOptions() { 
 | 
        this.msg = '' 
 | 
        this.backgroundColor = '' 
 | 
        this.fontColor = '' 
 | 
      }, 
 | 
    } 
 | 
  } 
 | 
</script> 
 | 
  
 | 
<style lang="scss" scoped> 
 | 
   
 | 
  /*注意问题: 
 | 
   1、fixed 元素宽度无法自适应,所以增加了子元素 
 | 
   2、fixed 和 display冲突导致动画效果消失,暂时使用visibility替代 
 | 
  */ 
 | 
  .tn-tips { 
 | 
    height: auto; 
 | 
    position: fixed; 
 | 
    box-sizing: border-box; 
 | 
    display: flex; 
 | 
    align-items: center; 
 | 
    justify-content: center; 
 | 
    transition: all 0.3s ease-in-out; 
 | 
    opacity: 0; 
 | 
     
 | 
    &__content { 
 | 
      word-wrap: break-word; 
 | 
      word-break: break-all; 
 | 
      width: 100%; 
 | 
      height: auto; 
 | 
      text-align: center; 
 | 
      background-color: rgba(0, 0, 0, 0.7); 
 | 
      color: #FFFFFF; 
 | 
    } 
 | 
     
 | 
    &--top { 
 | 
      width: 100% !important; 
 | 
      /* padding: 18rpx 30rpx; */ 
 | 
      top: 0; 
 | 
      left: 0; 
 | 
      transform: translateY(-100%) translateZ(0); 
 | 
      word-break: break-all; 
 | 
    } 
 | 
     
 | 
    &--center { 
 | 
      left: 50%; 
 | 
      top: 50%; 
 | 
      transform: translate(-50%, -50%); 
 | 
    } 
 | 
     
 | 
    &--bottom { 
 | 
      bottom: 120rpx; 
 | 
      left: 50%; 
 | 
      transform: translateX(-50%); 
 | 
    } 
 | 
     
 | 
    &--center, &--bottom { 
 | 
      .content { 
 | 
        border-radius: 8rpx; 
 | 
        padding: 0; 
 | 
      } 
 | 
    } 
 | 
     
 | 
    &--center, &--bottom { 
 | 
      .tn-tips__content { 
 | 
        padding: 18rpx 30rpx !important; 
 | 
      } 
 | 
    } 
 | 
     
 | 
    &--show { 
 | 
      opacity: 1; 
 | 
       
 | 
      &.tn-tips--top { 
 | 
        transform: translateY(0) translateZ(0) !important; 
 | 
      } 
 | 
    } 
 | 
     
 | 
  } 
 | 
   
 | 
</style> 
 |