CountDown.vue 2.17 KB
<template>
  <span>
    {{ lastTime | format }}
  </span>
</template>

<script>

  function fixedZero(val) {
    return val * 1 < 10 ? `0${val}` : val;
  }

  export default {
    name: "CountDown",
    props: {
      format: {
        type: Function,
        default: undefined
      },
      target: {
        type: [Date, Number],
        required: true,
      },
      onEnd: {
        type: Function,
        default: () => {
        }
      }
    },
    data() {
      return {
        dateTime: '0',
        originTargetTime: 0,
        lastTime: 0,
        timer: 0,
        interval: 1000
      }
    },
    filters: {
      format(time) {
        const hours = 60 * 60 * 1000;
        const minutes = 60 * 1000;

        const h = Math.floor(time / hours);
        const m = Math.floor((time - h * hours) / minutes);
        const s = Math.floor((time - h * hours - m * minutes) / 1000);
        return `${fixedZero(h)}:${fixedZero(m)}:${fixedZero(s)}`
      }
    },
    created() {
      this.initTime()
      this.tick()
    },
    methods: {
      initTime() {
        let lastTime = 0;
        let targetTime = 0;
        this.originTargetTime = this.target
        try {
          if (Object.prototype.toString.call(this.target) === '[object Date]') {
            targetTime = this.target
          } else {
            targetTime = new Date(this.target).getTime()
          }
        } catch (e) {
          throw new Error('invalid target prop')
        }

        lastTime = targetTime - new Date().getTime();

        this.lastTime = lastTime < 0 ? 0 : lastTime
      },
      tick() {
        const {onEnd} = this

        this.timer = setTimeout(() => {
          if (this.lastTime < this.interval) {
            clearTimeout(this.timer)
            this.lastTime = 0
            if (typeof onEnd === 'function') {
              onEnd();
            }
          } else {
            this.lastTime -= this.interval
            this.tick()
          }
        }, this.interval)
      }
    },
    beforeUpdate () {
      if (this.originTargetTime !== this.target) {
        this.initTime()
      }
    },
    beforeDestroy() {
      clearTimeout(this.timer)
    }
  }
</script>

<style scoped>

</style>