倒计时组件

<!--倒计时
使用说明:传入time(时间差 秒)
-->
<template>
    <div class="countdown">
        <slot v-if="format" :time="formatCountdown(timeDiff)"></slot>
        <slot v-else :time="timeDiff"></slot>
    </div>
</template>
<script>
export default {
    props: {
        // 时间差
        time: {
            type: Number,
            default: 60
        },
        // 步长
        step: {
            type: Number,
            default: 1
        },
        // 开关
        switch: {
            type: Boolean,
            default: null
        },
        // 格式化
        format: {
            type: String,
            default: ''
        }
    },
    data() {
        return {
            // 时间函数
            timer: null,
            // 倒计时
            timeDiff: 0
        };
    },
    computed: {
        // 步长转换为毫秒
        computedStep() {
            return this.step * 1000;
        }
    },
    watch: {
        // 监听倒计时时间差变化
        time: {
            handler(val) {
                this.timeDiff = val;
                const isSwitch = typeof this.switch === 'boolean';
                if(val && !this.timer) {
                    if(isSwitch) {
                        if(this.switch) {
                            this.triggerTimer();
                        } else {
                            this.clearTimer();
                        }
                    } else {
                        this.triggerTimer();
                    }
                } else {
                    this.clearTimer();
                }
            },
            immediate: true
        },
        // 监听开关变化
        switch: {
            handler(val) {
                if(val) {
                    this.triggerTimer();
                } else {
                    this.clearTimer();
                }
            }
        }
    },
    methods: {
        // 触发倒计时函数
        triggerTimer() {
            this.timer = setTimeout(() => {
                this.timeDiff--;
                if(this.timeDiff <= 0) {
                    this.$emit('on-end');
                } else {
                    this.$emit('on-countdown', this.timeDiff);
                    this.triggerTimer();
                }
            }, this.computedStep);
        },
        // 清除定时器
        clearTimer() {
            if(this.timer) {
                clearTimeout(this.timer);
            }
        },
        // 格式化时间戳
        formatCountdown(timeDiff) {
            // 获取还剩多少小时
            const hour = parseInt((timeDiff / 60 / 60).toString());

            // 获取还剩多少分钟
            let minute;
            if(this.format.includes('hh') || this.format.includes('HH')) {
                minute = parseInt(((timeDiff / 60) % 60).toString());
            } else {
                minute = parseInt((timeDiff / 60).toString());
            }

            // 获取还剩多少秒
            let second;
            if(this.format.includes('mm') || this.format.includes('MM')) {
                second = timeDiff % 60;
            } else {
                second = timeDiff;
            }

            let result = this.format;
            result = result.replace(/(hh|HH)/g, this.paddingZero(hour));
            result = result.replace(/(mm|MM)/g, this.paddingZero(minute));
            result = result.replace(/(ss|SS)/g, this.paddingZero(second));
            return result;
        },
        // 补零
        paddingZero(val) {
            if(val <= 0) {
                return '00';
            } else if(val < 10) {
                return `0${val}`;
            } else {
                return val.toString();
            }
        },
        // 重新倒计时
        reCountdown() {
            this.timeDiff = this.time;
        }
    },
    beforeDestroy() {
        this.clearTimer();
    }
};
</script>
<style lang="scss" scoped>
.countdown {
    display: inline-block;
}
</style>

推荐阅读更多精彩内容