<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> 
 |