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