blob: 7285d672179ea8d3088dfdb6bd567851baf1c7c6 [file] [log] [blame]
guangchao.xu070005a2020-12-07 09:56:40 +08001<template>
2 <view class="u-countdown">
3 <view class="u-countdown-item" :style="[itemStyle]" v-if="showDays && (hideZeroDay || (!hideZeroDay && d != '00'))">
4 <view class="u-countdown-time" :style="[letterStyle]">
5 {{ d }}
6 </view>
7 </view>
8 <view
9 class="u-countdown-colon"
10 :style="{fontSize: separatorSize + 'rpx', color: separatorColor, paddingBottom: separator == 'colon' ? '4rpx' : 0}"
11 v-if="showDays && (hideZeroDay || (!hideZeroDay && d != '00'))"
12 >
13 {{ separator == 'colon' ? ':' : '天' }}
14 </view>
15 <view class="u-countdown-item" :style="[itemStyle]" v-if="showHours">
16 <view class="u-countdown-time" :style="{ fontSize: fontSize + 'rpx', color: color}">
17 {{ h }}
18 </view>
19 </view>
20 <view
21 class="u-countdown-colon"
22 :style="{fontSize: separatorSize + 'rpx', color: separatorColor, paddingBottom: separator == 'colon' ? '4rpx' : 0}"
23 v-if="showHours"
24 >
25 {{ separator == 'colon' ? ':' : '时' }}
26 </view>
27 <view class="u-countdown-item" :style="[itemStyle]" v-if="showMinutes">
28 <view class="u-countdown-time" :style="{ fontSize: fontSize + 'rpx', color: color}">
29 {{ i }}
30 </view>
31 </view>
32 <view
33 class="u-countdown-colon"
34 :style="{fontSize: separatorSize + 'rpx', color: separatorColor, paddingBottom: separator == 'colon' ? '4rpx' : 0}"
35 v-if="showMinutes"
36 >
37 {{ separator == 'colon' ? ':' : '分' }}
38 </view>
39 <view class="u-countdown-item" :style="[itemStyle]" v-if="showSeconds">
40 <view class="u-countdown-time" :style="{ fontSize: fontSize + 'rpx', color: color}">
41 {{ s }}
42 </view>
43 </view>
44 <view
45 class="u-countdown-colon"
46 :style="{fontSize: separatorSize + 'rpx', color: separatorColor, paddingBottom: separator == 'colon' ? '4rpx' : 0}"
47 v-if="showSeconds && separator == 'zh'"
48 >
49
50 </view>
51 </view>
52</template>
53
54<script>
55/**
56 * countDown 倒计时
57 * @description 该组件一般使用于某个活动的截止时间上,通过数字的变化,给用户明确的时间感受,提示用户进行某一个行为操作。
58 * @tutorial https://www.uviewui.com/components/countDown.html
59 * @property {String Number} timestamp 倒计时,单位为秒
60 * @property {Boolean} autoplay 是否自动开始倒计时,如果为false,需手动调用开始方法。见官网说明(默认true)
61 * @property {String} separator 分隔符,colon为英文冒号,zh为中文(默认colon)
62 * @property {String Number} separator-size 分隔符的字体大小,单位rpx(默认30)
63 * @property {String} separator-color 分隔符的颜色(默认#303133)
64 * @property {String Number} font-size 倒计时字体大小,单位rpx(默认30)
65 * @property {Boolean} show-border 是否显示倒计时数字的边框(默认false)
66 * @property {Boolean} hide-zero-day 当"天"的部分为0时,隐藏该字段 (默认true)
67 * @property {String} border-color 数字边框的颜色(默认#303133)
68 * @property {String} bg-color 倒计时数字的背景颜色(默认#ffffff)
69 * @property {String} color 倒计时数字的颜色(默认#303133)
70 * @property {String} height 数字高度值(宽度等同此值),设置边框时看情况是否需要设置此值,单位rpx(默认auto)
71 * @property {Boolean} show-days 是否显示倒计时的"天"部分(默认true)
72 * @property {Boolean} show-hours 是否显示倒计时的"时"部分(默认true)
73 * @property {Boolean} show-minutes 是否显示倒计时的"分"部分(默认true)
74 * @property {Boolean} show-seconds 是否显示倒计时的"秒"部分(默认true)
75 * @event {Function} end 倒计时结束
76 * @event {Function} change 每秒触发一次,回调为当前剩余的倒计秒数
77 * @example <u-count-down ref="uCountDown" :timestamp="86400" :autoplay="false"></u-count-down>
78 */
79export default {
80 name: 'u-count-down',
81 props: {
82 // 倒计时的时间,秒为单位
83 timestamp: {
84 type: [Number, String],
85 default: 0
86 },
87 // 是否自动开始倒计时
88 autoplay: {
89 type: Boolean,
90 default: true
91 },
92 // 用英文冒号(colon)或者中文(zh)当做分隔符,false的时候为中文,如:"11:22"或"11时22秒"
93 separator: {
94 type: String,
95 default: 'colon'
96 },
97 // 分隔符的大小,单位rpx
98 separatorSize: {
99 type: [Number, String],
100 default: 30
101 },
102 // 分隔符颜色
103 separatorColor: {
104 type: String,
105 default: "#303133"
106 },
107 // 字体颜色
108 color: {
109 type: String,
110 default: '#303133'
111 },
112 // 字体大小,单位rpx
113 fontSize: {
114 type: [Number, String],
115 default: 30
116 },
117 // 背景颜色
118 bgColor: {
119 type: String,
120 default: '#fff'
121 },
122 // 数字框高度,单位rpx
123 height: {
124 type: [Number, String],
125 default: 'auto'
126 },
127 // 是否显示数字框
128 showBorder: {
129 type: Boolean,
130 default: false
131 },
132 // 边框颜色
133 borderColor: {
134 type: String,
135 default: '#303133'
136 },
137 // 是否显示秒
138 showSeconds: {
139 type: Boolean,
140 default: true
141 },
142 // 是否显示分钟
143 showMinutes: {
144 type: Boolean,
145 default: true
146 },
147 // 是否显示小时
148 showHours: {
149 type: Boolean,
150 default: true
151 },
152 // 是否显示“天”
153 showDays: {
154 type: Boolean,
155 default: true
156 },
157 // 当"天"的部分为0时,不显示
158 hideZeroDay: {
159 type: Boolean,
160 default: false
161 }
162 },
163 watch: {
164 // 监听时间戳的变化
165 timestamp(newVal, oldVal) {
166 // 如果倒计时间发生变化,清除定时器,重新开始倒计时
167 this.clearTimer();
168 this.start();
169 }
170 },
171 data() {
172 return {
173 d: '00', // 天的默认值
174 h: '00', // 小时的默认值
175 i: '00', // 分钟的默认值
176 s: '00', // 秒的默认值
177 timer: null ,// 定时器
178 seconds: 0, // 记录不停倒计过程中变化的秒数
179 };
180 },
181 computed: {
182 // 倒计时item的样式,item为分别的时分秒部分的数字
183 itemStyle() {
184 let style = {};
185 if(this.height) {
186 style.height = this.height + 'rpx';
187 style.width = this.height + 'rpx';
188 }
189 if(this.showBorder) {
190 style.borderStyle = 'solid';
191 style.borderColor = this.borderColor;
192 style.borderWidth = '1px';
193 }
194 if(this.bgColor) {
195 style.backgroundColor = this.bgColor;
196 }
197 return style;
198 },
199 // 倒计时数字的样式
200 letterStyle() {
201 let style = {};
202 if(this.fontSize) style.fontSize = this.fontSize + 'rpx';
203 if(this.color) style.color = this.color;
204 return style;
205 }
206 },
207 mounted() {
208 // 如果自动倒计时
209 this.autoplay && this.timestamp && this.start();
210 },
211 methods: {
212 // 倒计时
213 start() {
214 // 避免可能出现的倒计时重叠情况
215 this.clearTimer();
216 if (this.timestamp <= 0) return;
217 this.seconds = Number(this.timestamp);
218 this.formatTime(this.seconds);
219 this.timer = setInterval(() => {
220 this.seconds--;
221 // 发出change事件
222 this.$emit('change', this.seconds);
223 if (this.seconds < 0) {
224 return this.end();
225 }
226 this.formatTime(this.seconds);
227 }, 1000);
228 },
229 // 格式化时间
230 formatTime(seconds) {
231 // 小于等于0的话,结束倒计时
232 seconds <= 0 && this.end();
233 let [day, hour, minute, second] = [0, 0, 0, 0];
234 day = Math.floor(seconds / (60 * 60 * 24));
235 // 判断是否显示“天”参数,如果不显示,将天部分的值,加入到小时中
236 // hour为给后面计算秒和分等用的(基于显示天的前提下计算)
237 hour = Math.floor(seconds / (60 * 60)) - day * 24;
238 // showHour为需要显示的小时
239 let showHour = null;
240 if(this.showDays) {
241 showHour = hour;
242 } else {
243 // 如果不显示天数,将“天”部分的时间折算到小时中去
244 showHour = Math.floor(seconds / (60 * 60));
245 }
246 minute = Math.floor(seconds / 60) - hour * 60 - day * 24 * 60;
247 second = Math.floor(seconds) - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60;
248 // 如果小于10,在前面补上一个"0"
249 showHour = showHour < 10 ? '0' + showHour : showHour;
250 minute = minute < 10 ? '0' + minute : minute;
251 second = second < 10 ? '0' + second : second;
252 day = day < 10 ? '0' + day : day;
253 this.d = day;
254 this.h = showHour;
255 this.i = minute;
256 this.s = second;
257 },
258 // 停止倒计时
259 end() {
260 this.clearTimer();
261 this.$emit('end', {});
262 },
263 // 清除定时器
264 clearTimer() {
265 if(this.timer) {
266 // 清除定时器
267 clearInterval(this.timer);
268 this.timer = null;
269 }
270 }
271 },
272 beforeDestroy() {
273 clearInterval(this.timer);
274 this.timer = null;
275 }
276};
277</script>
278
279<style scoped lang="scss">
280 @import "../../libs/css/style.components.scss";
281
282 .u-countdown {
283 /* #ifndef APP-NVUE */
284 display: inline-flex;
285 /* #endif */
286 align-items: center;
287 }
288
289 .u-countdown-item {
290 @include vue-flex;
291 align-items: center;
292 justify-content: center;
293 padding: 2rpx;
294 border-radius: 6rpx;
295 white-space: nowrap;
296 transform: translateZ(0);
297 }
298
299 .u-countdown-time {
300 margin: 0;
301 padding: 0;
302 line-height: 1;
303 }
304
305 .u-countdown-colon {
306 @include vue-flex;
307 justify-content: center;
308 padding: 0 5rpx;
309 line-height: 1;
310 align-items: center;
311 padding-bottom: 4rpx;
312 }
313
314 .u-countdown-scale {
315 transform: scale(0.9);
316 transform-origin: center center;
317 }
318</style>