<template>  
 | 
    <view class="u-count-down">  
 | 
        <slot>  
 | 
            <text class="u-count-down__text">{{ formattedTime }}</text>  
 | 
        </slot>  
 | 
    </view>  
 | 
</template>  
 | 
  
 | 
<script>  
 | 
    import props from './props.js';  
 | 
    import {  
 | 
        isSameSecond,  
 | 
        parseFormat,  
 | 
        parseTimeData  
 | 
    } from './utils';  
 | 
    /**  
 | 
     * u-count-down 倒计时  
 | 
     * @description 该组件一般使用于某个活动的截止时间上,通过数字的变化,给用户明确的时间感受,提示用户进行某一个行为操作。  
 | 
     * @tutorial https://uviewui.com/components/countDown.html  
 | 
     * @property {String | Number}    time        倒计时时长,单位ms (默认 0 )  
 | 
     * @property {String}            format        时间格式,DD-日,HH-时,mm-分,ss-秒,SSS-毫秒  (默认 'HH:mm:ss' )  
 | 
     * @property {Boolean}            autoStart    是否自动开始倒计时 (默认 true )  
 | 
     * @property {Boolean}            millisecond    是否展示毫秒倒计时 (默认 false )  
 | 
     * @event {Function} finish 倒计时结束时触发   
 | 
     * @event {Function} change 倒计时变化时触发   
 | 
     * @event {Function} start    开始倒计时  
 | 
     * @event {Function} pause    暂停倒计时   
 | 
     * @event {Function} reset    重设倒计时,若 auto-start 为 true,重设后会自动开始倒计时   
 | 
     * @example <u-count-down :time="time"></u-count-down>  
 | 
     */  
 | 
    export default {  
 | 
        name: 'u-count-down',  
 | 
        mixins: [uni.$u.mpMixin, uni.$u.mixin, props],  
 | 
        data() {  
 | 
            return {  
 | 
                timer: null,  
 | 
                // 各单位(天,时,分等)剩余时间  
 | 
                timeData: parseTimeData(0),  
 | 
                // 格式化后的时间,如"03:23:21"  
 | 
                formattedTime: '0',  
 | 
                // 倒计时是否正在进行中  
 | 
                runing: false,  
 | 
                endTime: 0, // 结束的毫秒时间戳  
 | 
                remainTime: 0, // 剩余的毫秒时间  
 | 
            }  
 | 
        },  
 | 
        watch: {  
 | 
            time(n) {  
 | 
                this.reset()  
 | 
            }  
 | 
        },  
 | 
        mounted() {  
 | 
            this.init()  
 | 
        },  
 | 
        methods: {  
 | 
            init() {  
 | 
                this.reset()  
 | 
            },  
 | 
            // 开始倒计时  
 | 
            start() {  
 | 
                if (this.runing) return  
 | 
                // 标识为进行中  
 | 
                this.runing = true  
 | 
                // 结束时间戳 = 此刻时间戳 + 剩余的时间  
 | 
                this.endTime = Date.now() + this.remainTime  
 | 
                this.toTick()  
 | 
            },  
 | 
            // 根据是否展示毫秒,执行不同操作函数  
 | 
            toTick() {  
 | 
                if (this.millisecond) {  
 | 
                    this.microTick()  
 | 
                } else {  
 | 
                    this.macroTick()  
 | 
                }  
 | 
            },  
 | 
            macroTick() {  
 | 
                this.clearTimeout()  
 | 
                // 每隔一定时间,更新一遍定时器的值  
 | 
                // 同时此定时器的作用也能带来毫秒级的更新  
 | 
                this.timer = setTimeout(() => {  
 | 
                    // 获取剩余时间  
 | 
                    const remain = this.getRemainTime()  
 | 
                    // 重设剩余时间  
 | 
                    if (!isSameSecond(remain, this.remainTime) || remain === 0) {  
 | 
                        this.setRemainTime(remain)  
 | 
                    }  
 | 
                    // 如果剩余时间不为0,则继续检查更新倒计时  
 | 
                    if (this.remainTime !== 0) {  
 | 
                        this.macroTick()  
 | 
                    }  
 | 
                }, 30)  
 | 
            },  
 | 
            microTick() {  
 | 
                this.clearTimeout()  
 | 
                this.timer = setTimeout(() => {  
 | 
                    this.setRemainTime(this.getRemainTime())  
 | 
                    if (this.remainTime !== 0) {  
 | 
                        this.microTick()  
 | 
                    }  
 | 
                }, 50)  
 | 
            },  
 | 
            // 获取剩余的时间  
 | 
            getRemainTime() {  
 | 
                // 取最大值,防止出现小于0的剩余时间值  
 | 
                return Math.max(this.endTime - Date.now(), 0)  
 | 
            },  
 | 
            // 设置剩余的时间  
 | 
            setRemainTime(remain) {  
 | 
                this.remainTime = remain  
 | 
                // 根据剩余的毫秒时间,得出该有天,小时,分钟等的值,返回一个对象  
 | 
                const timeData = parseTimeData(remain)  
 | 
                this.$emit('change', timeData)  
 | 
                // 得出格式化后的时间  
 | 
                this.formattedTime = parseFormat(this.format, timeData)  
 | 
                // 如果时间已到,停止倒计时  
 | 
                if (remain <= 0) {  
 | 
                    this.pause()  
 | 
                    this.$emit('finish')  
 | 
                }  
 | 
            },  
 | 
            // 重置倒计时  
 | 
            reset() {  
 | 
                this.pause()  
 | 
                this.remainTime = this.time  
 | 
                this.setRemainTime(this.remainTime)  
 | 
                if (this.autoStart) {  
 | 
                    this.start()  
 | 
                }  
 | 
            },  
 | 
            // 暂停倒计时  
 | 
            pause() {  
 | 
                this.runing = false;  
 | 
                this.clearTimeout()  
 | 
            },  
 | 
            // 清空定时器  
 | 
            clearTimeout() {  
 | 
                clearTimeout(this.timer)  
 | 
                this.timer = null  
 | 
            }  
 | 
        },  
 | 
        beforeDestroy() {  
 | 
            this.clearTimeout()  
 | 
        }  
 | 
    }  
 | 
</script>  
 | 
  
 | 
<style  
 | 
    lang="scss"  
 | 
    scoped  
 | 
>  
 | 
    @import "../../libs/css/components.scss";  
 | 
    $u-count-down-text-color:$u-content-color !default;  
 | 
    $u-count-down-text-font-size:15px !default;  
 | 
    $u-count-down-text-line-height:22px !default;  
 | 
  
 | 
    .u-count-down {  
 | 
        &__text {  
 | 
            color: $u-count-down-text-color;  
 | 
            font-size: $u-count-down-text-font-size;  
 | 
            line-height: $u-count-down-text-line-height;  
 | 
        }  
 | 
    }  
 | 
</style> 
 |