使用

使用背景:发送短信或者发送验证码时的多少秒倒数,定时执行多次轮询的请求

// 引入倒计时类(class)
import { BuildCountdown } from '@/constance/countdown.js'

// 再需要的地方实例化一个countdown 对象
let countdown = new BuildCountdown(option,callback)

`还有${countdown.count}秒`


参数说明

第一个参数 option ,是一个配置对象 Object 类型

  • option.count Number类型 需要倒数的数值 默认10
  • option.unit String类型 本次倒计时 数值的单位 默认 s,d(天)、h(小时)、m(分钟)、s(秒)、ms(毫秒)
  • option.awaitTime Number类型 倒计时的间隔时间 默认1

第二个参数 callback ,是到时间结束,即 conut为0时执行的函数

new BuildCountdown({count: 1000, unit: 'ms', awaitTime: 1},() => {})


实例属性说明

  • countdown.count 倒数变化的数值
  • countdown.day 倒计时剩余天数
  • countdown.hour 倒计时剩余小时数
  • countdown.minute倒计时剩余分钟数
  • countdown.seconds 倒计时剩余秒数
  • countdown.millisecond 倒计时剩余毫秒数

day、hour、minute、seconds、millisecond 这些属性是不能通过countdown对象遍历出来的

// vue 的 computed 计算属性 
computed:{
tieme () {
return `${this.countdown.hour}时${this.countdown.minute}分${this.countdown.seconds}秒${this.countdown.millisecond}毫秒`
}
}


实例方法说明

  • countdown.suspend() 倒计时暂停
  • countdown.start() 倒计时暂停之后 开始执行
  • countdown.refreshTimer() 刷新倒计时 重新开始倒计时
  • countdown.removeTimer() 移除倒计时 不会执行回调函数
  • countdown.handleTimeEnd() 结束倒计时 会执行回调函数
// vue 的 beforeDestroy 离开页面时 清楚倒计时
beforeDestroy() {
this.countdown.removeTimer && this.countdown.removeTimer()
}


源码

---copy
/**
* @param {option} 毫秒数
* @param { option.count } 倒数的数值 默认10
* @param { option.unit } 倒数的数值的单位 d天 h小时 m分钟 s秒(默认) ms毫秒
* @param { option.awaitTime } 倒计时间隔时间数值 也是根据单位来确定具体时间
* @param {timeEndCallback} 倒计时结束回调
*
*/

export class BuildCountdown {
constructor (option, timeEndCallback) {
let {count, rotate, awaitTime } = BuildCountdown.filterOption(option)
this.count = count // 倒计时的数字
this.rotate = rotate // 单位换算成毫秒的比例
this.countValue= count // 倒计时的原始数字
this.awaitTime = awaitTime // setTime 的间隔时间
this.timeEndCallback = timeEndCallback
this.setTimer()
}
timer = null

static filterOption (option) {
// 分别计算出 一天、一小时等几毫秒
let dateMap = {
d: 1000 * 60 * 60 * 24,
h: 1000 * 60 * 60,
m: 1000 * 60,
s: 1000,
ms: 1
}
option = {
count: 10,
unit: 's',
awaitTime: 1,
...option
}
let result = {
count: option.count * 1,
rotate: dateMap[option.unit] || 1000
}
result.awaitTime = (option.unit === 'ms' && option.awaitTime < 9) ? 9 : option.awaitTime
return result
}

get inCountdown () {
return !!this.timer
}
get inCountdown () {
return !!this.timer
}
get day () {
return this.filterString(Math.floor((this.rotate * this.count) / (1000 * 60 * 60 * 24)))
}
get hour () {
return this.filterString(Math.floor((this.rotate * this.count) % (1000 * 60 * 60 * 24) / (1000 * 60 * 60)))
}
get minute () {
return this.filterString(Math.floor((this.rotate * this.count) % (1000 * 60 * 60 * 24) % (1000 * 60 * 60) / (1000 * 60)))
}
get seconds () {
return this.filterString(Math.floor((this.rotate * this.count) % (1000 * 60 * 60 * 24) % (1000 * 60 * 60) % (1000 * 60) / 1000))
}
get millisecond () {
return this.filterString(Math.floor((this.rotate * this.count) % (1000 * 60 * 60 * 24) % (1000 * 60 * 60) % (1000 * 60) % 1000), 3)
}

// 创建定时器
setTimer () {
if (this.count <= 0) return
this.timer = setInterval(() => {
if (this.count <= 0) return this.handleTimeEnd()
this.count = this.count - this.awaitTime
}, this.awaitTime * this.rotate)
}
// 暂停
suspend () {
clearInterval(this.timer)
}
// 开始计时
start () {
this.removeTimer()
this.setTimer()
}
// 刷新定时器
refreshTimer () {
this.removeTimer()
this.count = this.countValue
this.setTimer()
}
// 结束倒计时
handleTimeEnd () {
this.count = 0
this.removeTimer()
this.timeEndCallback && this.timeEndCallback()
}
// 移除倒计时
removeTimer () {
clearInterval(this.timer)
this.timer = null
}
// 格式化数字
filterString (value, num = 2) {
return (value + '').padEnd(num, '0')
}
}


知识点

  • 设置对象的 get set 属性时, 该属性不可以被遍历,不可以通过 for in 或者 Object.keys() 获取
  • 30 % 24 计算还有多少小时 应该把天先减去, 30模24等于6 还剩1天6小时
  • 倒计时毫秒时 因为setTimeout或者setInterval 最小间隔时间在4毫秒左右,不能真正做到1毫秒执行一次,这里选择使用最低9秒执行一次,为什么要用9?因为9乘以0到9 最终的个位数0~9这十个数都会出现,倒计时减9时,这样最后一位0到9都会出现,看着会更真实。
  • 多个参数的默认值就使用对象,就可以不用关注参数的顺序,只填写我们想要的
    option = {
count: 10,
unit: 's',
awaitTime: 1,
...option
}