zhangmeng
2024-04-19 e3ba120cb766a17e098e58d11c39ffc600a3070c
commit | author | age
e3ba12 1 <template>
Z 2     <view class="u-count-down">
3         <slot>
4             <text class="u-count-down__text">{{ formattedTime }}</text>
5         </slot>
6     </view>
7 </template>
8
9 <script>
10     import props from './props.js';
11     import {
12         isSameSecond,
13         parseFormat,
14         parseTimeData
15     } from './utils';
16     /**
17      * u-count-down 倒计时
18      * @description 该组件一般使用于某个活动的截止时间上,通过数字的变化,给用户明确的时间感受,提示用户进行某一个行为操作。
19      * @tutorial https://uviewui.com/components/countDown.html
20      * @property {String | Number}    time        倒计时时长,单位ms (默认 0 )
21      * @property {String}            format        时间格式,DD-日,HH-时,mm-分,ss-秒,SSS-毫秒  (默认 'HH:mm:ss' )
22      * @property {Boolean}            autoStart    是否自动开始倒计时 (默认 true )
23      * @property {Boolean}            millisecond    是否展示毫秒倒计时 (默认 false )
24      * @event {Function} finish 倒计时结束时触发 
25      * @event {Function} change 倒计时变化时触发 
26      * @event {Function} start    开始倒计时
27      * @event {Function} pause    暂停倒计时 
28      * @event {Function} reset    重设倒计时,若 auto-start 为 true,重设后会自动开始倒计时 
29      * @example <u-count-down :time="time"></u-count-down>
30      */
31     export default {
32         name: 'u-count-down',
33         mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
34         data() {
35             return {
36                 timer: null,
37                 // 各单位(天,时,分等)剩余时间
38                 timeData: parseTimeData(0),
39                 // 格式化后的时间,如"03:23:21"
40                 formattedTime: '0',
41                 // 倒计时是否正在进行中
42                 runing: false,
43                 endTime: 0, // 结束的毫秒时间戳
44                 remainTime: 0, // 剩余的毫秒时间
45             }
46         },
47         watch: {
48             time(n) {
49                 this.reset()
50             }
51         },
52         mounted() {
53             this.init()
54         },
55         methods: {
56             init() {
57                 this.reset()
58             },
59             // 开始倒计时
60             start() {
61                 if (this.runing) return
62                 // 标识为进行中
63                 this.runing = true
64                 // 结束时间戳 = 此刻时间戳 + 剩余的时间
65                 this.endTime = Date.now() + this.remainTime
66                 this.toTick()
67             },
68             // 根据是否展示毫秒,执行不同操作函数
69             toTick() {
70                 if (this.millisecond) {
71                     this.microTick()
72                 } else {
73                     this.macroTick()
74                 }
75             },
76             macroTick() {
77                 this.clearTimeout()
78                 // 每隔一定时间,更新一遍定时器的值
79                 // 同时此定时器的作用也能带来毫秒级的更新
80                 this.timer = setTimeout(() => {
81                     // 获取剩余时间
82                     const remain = this.getRemainTime()
83                     // 重设剩余时间
84                     if (!isSameSecond(remain, this.remainTime) || remain === 0) {
85                         this.setRemainTime(remain)
86                     }
87                     // 如果剩余时间不为0,则继续检查更新倒计时
88                     if (this.remainTime !== 0) {
89                         this.macroTick()
90                     }
91                 }, 30)
92             },
93             microTick() {
94                 this.clearTimeout()
95                 this.timer = setTimeout(() => {
96                     this.setRemainTime(this.getRemainTime())
97                     if (this.remainTime !== 0) {
98                         this.microTick()
99                     }
100                 }, 50)
101             },
102             // 获取剩余的时间
103             getRemainTime() {
104                 // 取最大值,防止出现小于0的剩余时间值
105                 return Math.max(this.endTime - Date.now(), 0)
106             },
107             // 设置剩余的时间
108             setRemainTime(remain) {
109                 this.remainTime = remain
110                 // 根据剩余的毫秒时间,得出该有天,小时,分钟等的值,返回一个对象
111                 const timeData = parseTimeData(remain)
112                 this.$emit('change', timeData)
113                 // 得出格式化后的时间
114                 this.formattedTime = parseFormat(this.format, timeData)
115                 // 如果时间已到,停止倒计时
116                 if (remain <= 0) {
117                     this.pause()
118                     this.$emit('finish')
119                 }
120             },
121             // 重置倒计时
122             reset() {
123                 this.pause()
124                 this.remainTime = this.time
125                 this.setRemainTime(this.remainTime)
126                 if (this.autoStart) {
127                     this.start()
128                 }
129             },
130             // 暂停倒计时
131             pause() {
132                 this.runing = false;
133                 this.clearTimeout()
134             },
135             // 清空定时器
136             clearTimeout() {
137                 clearTimeout(this.timer)
138                 this.timer = null
139             }
140         },
141         beforeDestroy() {
142             this.clearTimeout()
143         }
144     }
145 </script>
146
147 <style
148     lang="scss"
149     scoped
150 >
151     @import "../../libs/css/components.scss";
152     $u-count-down-text-color:$u-content-color !default;
153     $u-count-down-text-font-size:15px !default;
154     $u-count-down-text-line-height:22px !default;
155
156     .u-count-down {
157         &__text {
158             color: $u-count-down-text-color;
159             font-size: $u-count-down-text-font-size;
160             line-height: $u-count-down-text-line-height;
161         }
162     }
163 </style>