<template>
  <view
    class="u-transition"
    :class="animation"
    :style="[transitionStyle]"
    :hidden="hidden"
  >
    <slot />
  </view>
</template>

<script>
/**
 * transition 过度动画
 * @description 此组件为一个过度动画组件，目前用在uView的pageContainer页面加载动画组件的正在加载状态场景。
 * @tutorial https://www.uviewui.com/components/transition.html
 * @property {Boolean} show 是否显示动画（默认false）
 * @property {String} name 动画名称（默认none）
 * @property {String} inName 入场动画（默认none），设置后 name 将失效
 * @property {String} outName 出入场动画（默认none），设置后 name 将失效
 * @property {String} timingFunction 动画执行函数
 * @property {String Number} duration 动画持续时间
 * @property {String Number} delay 动画延迟执行时间
 * @example <u-transition name="fade"></u-transition>
 */

export default {
  name: 'u-transition',

  props: {
    // 是否展示组件
    show: {
      type: Boolean,
      default: false,
    },
    // 动画名称，不可与inName、outName同时使用，inName、outName的优先级高于name，默认inName与outName相同
    // none|fade|fadeLeft|fadeUp|fadeRight|fadeDown|zoom|bounce
    name: {
      type: String,
      default: '',
    },
    // 入场动画名称，设置时，name将失效，需要与outName搭配使用，如果outName未设置，则将使用与inName相同的出场动画
    inName: {
      type: String,
      default: '',
    },
    // 出场动画名称，设置时，name将失效，需要与inName搭配使用，如果inName未设置，则将使用与outName相同的入场动画
    outName: {
      type: String,
      default: '',
    },
    // 动画执行函数，可选值(linear|ease|ease-in|ease-out|ease-in-out|cubic-bezier(n,n,n,n))
    timingFunction: {
      type: String,
      default: 'linear',
    },
    // 动画持续时长(毫秒)
    duration: {
      type: [Number, String],
      default: 300,
    },
    // 动画执行延迟时间(毫秒)
    delay: {
      type: [Number, String],
      default: 0,
    },
    width: {
      type: String,
      default: 'auto',
    },
    height: {
      type: String,
      default: 'auto',
    },
  },

  data() {
    return {
      hidden: false,
      animationType: 'in', // 动画类型，是进入还是离开
    }
  },

  computed: {
    animation() {
      let ani = ''
      let name = this.name === 'none' ? '' : this.name
      let inName = this.inName === 'none' ? '' : this.inName
      let outName = this.outName === 'none' ? '' : this.outName
      if (inName && !outName) {
        ani = inName
      } else if (!inName && outName) {
        ani = outName
      } else if (inName && outName) {
        ani = this.show ? inName : outName
      } else if (name) {
        ani = name
      }
      if (ani === '') {
        return ''
      }
      ani = ani.replace(/([A-Z])/g, '-$1').toLowerCase()
      return `u-${ani}-${this.animationType}`
    },

    transitionStyle() {
      return {
        width: this.$u.addUnit(this.width),
        height: this.$u.addUnit(this.height),
        animationDuration: this.duration + 'ms',
        animationTimingFunction: this.timingFunction,
        animationDelay: this.delay + 'ms',
      }
    },
  },

  watch: {
    show(newVal, oldVal) {
      if (newVal && !oldVal) {
        this.animationType = 'in'
      } else if (!newVal && oldVal) {
        this.animationType = 'out'
      }

      // 执行动画之前，如果存在定时器，先清除，防止多次触发
      if (this.beforeTime) {
        clearTimeout(this.beforeTime)
      }
      this.beforeTime = setTimeout(() => {
        this.hidden = false
        this.beforeTime = undefined
        this.$emit('before')
      }, this.delay)

      // 执行动画之后，如果存在定时器，先清除，防止多次触发
      if (this.afterTime) {
        clearTimeout(this.afterTime)
      }
      this.afterTime = setTimeout(() => {
        !newVal && (this.hidden = true)
        this.afterTime = undefined
        this.$emit('after')
      }, this.delay + this.duration)
    },
  },

  methods: {},
}
</script>

<style lang="scss" scoped>
$distance: 50%;

.u-transition {
  animation-fill-mode: both;
}

// fade-in
.u-fade-in {
  animation-name: fadeIn;
}
@keyframes fadeIn {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

// fade-out
.u-fade-out {
  animation-name: fadeOut;
}
@keyframes fadeOut {
  0% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}

// fade-left-in
.u-fade-left-in {
  animation-name: fadeLeftIn;
}
@keyframes fadeLeftIn {
  0% {
    opacity: 0;
    transform: translateX(-#{$distance});
  }
  100% {
    opacity: 1;
    transform: translateX(0);
  }
}

// fade-left-out
.u-fade-left-out {
  animation-name: fadeLeftOut;
}
@keyframes fadeLeftOut {
  0% {
    opacity: 1;
    transform: translateX(0);
  }
  100% {
    opacity: 0;
    transform: translateX(-#{$distance});
  }
}

// fade-up-in
.u-fade-up-in {
  animation-name: fadeUpIn;
}
@keyframes fadeUpIn {
  0% {
    opacity: 0;
    transform: translateY(#{$distance});
  }
  100% {
    opacity: 1;
    transform: translateY(0);
  }
}

// fade-up-out
.u-fade-up-out {
  animation-name: fadeUpOut;
}
@keyframes fadeUpOut {
  0% {
    opacity: 1;
    transform: translateY(0);
  }
  100% {
    opacity: 0;
    transform: translateY(#{$distance});
  }
}

// fade-right-in
.u-fade-right-in {
  animation-name: fadeRightIn;
}
@keyframes fadeRightIn {
  0% {
    opacity: 0;
    transform: translateX(#{$distance});
  }
  100% {
    opacity: 1;
    transform: translateX(0);
  }
}

// fade-right-out
.u-fade-right-out {
  animation-name: fadeRightOut;
}
@keyframes fadeRightOut {
  0% {
    opacity: 1;
    transform: translateX(0);
  }
  100% {
    opacity: 0;
    transform: translateX(#{$distance});
  }
}

// fade-down-in
.u-fade-down-in {
  animation-name: fadeDownIn;
}
@keyframes fadeDownIn {
  0% {
    opacity: 0;
    transform: translateY(-#{$distance});
  }
  100% {
    opacity: 1;
    transform: translateY(0);
  }
}

// fade-down-out
.u-fade-down-out {
  animation-name: fadeDownOut;
}
@keyframes fadeDownOut {
  0% {
    opacity: 1;
    transform: translateY(0);
  }
  100% {
    opacity: 0;
    transform: translateY(-#{$distance});
  }
}

// zoom-in
.u-zoom-in {
  animation-name: zoomIn;
}
@keyframes zoomIn {
  0% {
    opacity: 0;
    transform: scale(0.2);
  }
  100% {
    opacity: 1;
    transform: scale(1);
  }
}

//-zoom-out
.u-zoom-out {
  animation-name: zoomOut;
}
@keyframes zoomOut {
  0% {
    opacity: 1;
    transform: scale(1);
  }
  100% {
    opacity: 0;
    transform: scale(0.2);
  }
}

// fade-bounce-in
.u-bounce-in {
  animation-name: bounceIn;
}
@keyframes bounceIn {
  0% {
    opacity: 0;
    transform: scale(5);
  }
  100% {
    opacity: 1;
    transform: scale(1);
  }
}

// fade-bounce-out
.u-bounce-out {
  animation-name: fadeBounceOut;
}
@keyframes fadeBounceOut {
  0% {
    opacity: 1;
    transform: scale(1);
  }
  100% {
    opacity: 0;
    transform: scale(8);
  }
}
</style>
