164 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Vue
		
	
	
	
		
		
			
		
	
	
			164 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Vue
		
	
	
	
| 
								 | 
							
								<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>
							 |