消息提示 u-totast

188 阅读1分钟
<template>
  <view
    class="u-toast"
    :class="[isShow ? 'u-show' : '','u-position-' + config.position,config.icon?'has-icon':'']"
    :style="{
		zIndex: uZIndex
	}"
  >
    <view class="u-icon-wrap">
        <image src="/static/base-module/toast-icon/success.png" v-if="config.type==='success'&&config.icon" class="success icon"></image>
        <image src="/static/base-module/toast-icon/warning.png" v-if="config.type==='warning'&&config.icon" class="warning icon"></image>
        <image src="/static/base-module/toast-icon/error.png" v-if="config.type==='error'&&config.icon" class="error icon"></image>
        <image src="/static/base-module/toast-icon/loading.png" v-if="config.type==='loading'&&config.icon" class="loading icon"></image>
    </view>
    <text class="u-text" :class="[config.icon?'icon-text':'']">{{config.title}}</text>
  </view>
</template>

<script>
/**
 * toast 消息提示
 * @description 此组件表现形式类似uni的uni.showToastAPI,但也有不同的地方。
 * @tutorial https://www.uviewui.com/components/toast.html
 * @property {String} z-index toast展示时的z-index值
 * @event {Function} show 显示toast,如需一进入页面就显示toast,请在onReady生命周期调用
 * @example <u-toast ref="uToast" />
 */
export default {
  name: 'u-toast',
  props: {
    // z-index值
    zIndex: {
      type: [Number, String],
      default: ''
    }
  },
  data() {
    return {
      isShow: false,
      timer: null, // 定时器
      config: {
        params: {}, // URL跳转的参数,对象
        title: '', // 显示文本
        type: '', // 主题类型,primary,success,error,warning,black
        duration: 2000, // 显示的时间,毫秒
        isTab: false, // 是否跳转tab页面
        url: '', // toast消失后是否跳转页面,有则跳转,优先级高于back参数
        icon: false, // 显示的图标
        position: 'center', // toast出现的位置
        callback: null, // 执行完后的回调函数
        back: false // 结束toast是否自动返回上一页
      }
    }
  },
  computed: {
    iconName() {
      // 只有不为none,并且type为error|warning|succes|info时候,才显示图标
      if (
        ['error', 'warning', 'success', 'info'].indexOf(this.config.type) >=
          0 &&
        this.config.icon
      ) {
        let icon = this.$u.type2icon(this.config.type)
        return icon
      }
    },
    uZIndex() {
      // 显示toast时候,如果用户有传递z-index值,有限使用
      return this.isShow
        ? this.zIndex
          ? this.zIndex
          : this.$u.zIndex.toast
        : '999999'
    }
  },
  methods: {
    // 显示toast组件,由父组件通过this.$refs.xxx.show(options)形式调用
    show(options) {
      this.config = this.$u.deepMerge(this.config, options)
      if (this.timer) {
        // 清除定时器
        clearTimeout(this.timer)
        this.timer = null
      }
      this.isShow = true
      this.timer = setTimeout(() => {
        // 倒计时结束,清除定时器,隐藏toast组件
        this.isShow = false
        clearTimeout(this.timer)
        this.timer = null
        // 判断是否存在callback方法,如果存在就执行
        typeof this.config.callback === 'function' && this.config.callback()
        this.timeEnd()
      }, this.config.duration)
    },
    // 隐藏toast组件,由父组件通过this.$refs.xxx.hide()形式调用
    hide() {
      this.isShow = false
      if (this.timer) {
        // 清除定时器
        clearTimeout(this.timer)
        this.timer = null
      }
    },
    // 倒计时结束之后,进行的一些操作
    timeEnd() {
      // 如果带有url值,根据isTab为true或者false进行跳转
      if (this.config.url) {
        // 如果url没有"/"开头,添加上,因为uni的路由跳转需要"/"开头
        if (this.config.url[0] != '/') this.config.url = '/' + this.config.url
        // 判断是否有传递显式的参数
        if (Object.keys(this.config.params).length) {
          // 判断用户传递的url中,是否带有参数
          // 使用正则匹配,主要依据是判断是否有"/","?","="等,如“/page/index/index?name=mary"
          // 如果有params参数,转换后无需带上"?"
          let query = ''
          if (/.*\/.*\?.*=.*/.test(this.config.url)) {
            // object对象转为get类型的参数
            query = this.$u.queryParams(this.config.params, false)
            this.config.url = this.config.url + '&' + query
          } else {
            query = this.$u.queryParams(this.config.params)
            this.config.url += query
          }
        }
        // 如果是跳转tab页面,就使用uni.switchTab
        if (this.config.isTab) {
          uni.switchTab({
            url: this.config.url
          })
        } else {
          uni.navigateTo({
            url: this.config.url
          })
        }
      } else if (this.config.back) {
        // 回退到上一页
        this.$u.route({
          type: 'back'
        })
      }
    }
  }
}
</script>

<style lang="scss" scoped>
@import '../../libs/css/style.components.scss';

.u-toast {
  position: fixed;
  z-index: -1;
  transition: opacity 0.3s;
  text-align: center;
  color:rgba(255,255,255,1);
  border-radius: rpx(88);
  background:rgba(0,0,0,0.6);
  min-height: rpx(120);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  font-size: rpx(40);
  opacity: 0;
  pointer-events: none;
  padding: 0 rpx(60);
  min-width: rpx(520);
  max-width: rpx(1120);
}
.has-icon{
   background:rgba(0,0,0,0.6);
   border-radius:rpx(16);
   min-width: rpx(490);
   max-width: rpx(632);
   word-wrap:break-word;
   padding:rpx(90) rpx(30) rpx(96) rpx(30);
}
.u-toast.u-show {
  opacity: 1;
}

.u-text {
  word-wrap:break-word;
  font-size:rpx(40);
  color:rgba(255,255,255,1);
}
.icon-text{
  font-size:rpx(46);
  font-weight:400;
  color:rgba(255,255,255,1);
  word-wrap:break-word;
}
.u-icon {
  margin-right: 5rpx;
  display: flex;
  align-items: center;
  line-height: normal;
}
.icon{
  width: rpx(172);
  height: rpx(172);
  margin-bottom: rpx(48);
}
.loading {
    animation: loading 1s steps(8) infinite;
}
@keyframes loading {
    from {transform: rotate(0deg);}
      to {transform: rotate(360deg);}
}
.u-position-center {
  left: 50%;
  top: 50%;
  transform: translateX(-50%) translateY(-50%);
}

.u-position-top {
  left: 50%;
  top: 20%;
  transform: translateX(-50%) translateY(-50%);
}

.u-position-bottom {
  left: 50%;
  bottom: 20%;
  transform: translateX(-50%) translateY(-50%);
}
</style>