import { ref, Ref } from 'vue' interface CountdownTimerOptions { delay?: number cacheKey?: string } /** * 倒计时 * - Ref countdown、isCounting * - Fn start、stop */ class CountdownTimer { delay: number cacheKey: string isCounting: Ref countdown: Ref countdownTimer: any constructor({ delay, cacheKey }: CountdownTimerOptions = {}) { this.delay = delay || 59 this.cacheKey = cacheKey || 'sms-count-timer' this.isCounting = ref(false) this.countdown = ref(0) this.countdownTimer = null this.recoverCacheCountdown() } /** * 对外提供调用 */ getInstance() { return { countdown: this.countdown, isCounting: this.isCounting, start: this.startCountdown.bind(this), stop: this.stopTimer.bind(this) } } /** * 开始倒计时 */ startCountdown() { if (!this.isCounting.value) { if (this.cacheKey) { localStorage.setItem(this.cacheKey, Date.now().toString()) } this.countdown.value = this.delay this.startTimer() } } /** * 恢复缓存倒计时 */ recoverCacheCountdown() { if (this.cacheKey && localStorage.getItem(this.cacheKey)) { const cacheDelay = this.calcCountdown( parseInt(localStorage.getItem(this.cacheKey)) ) if (cacheDelay) { this.countdown.value = cacheDelay this.startTimer() } } } /** * 计算倒计时,如果超过60秒则不再计算 * @param start - 需要与当前时间对比的开始时间,ms */ calcCountdown(start) { const startTime = parseInt(start) || Date.now() const diffTime = Math.ceil((Date.now() - startTime) / 1000) if (diffTime > 0 && diffTime <= this.delay) { return this.delay - diffTime } return 0 } /** * 开始倒计时 */ startTimer() { this.isCounting.value = true this.countdownTimer = setInterval(() => { this.countdown.value-- if (this.countdown.value <= 0) { this.isCounting.value = false clearInterval(this.countdownTimer) if (this.cacheKey) { localStorage.removeItem(this.cacheKey) } } }, 1000) } /** * 停止倒计时 */ stopTimer() { clearInterval(this.countdownTimer) } } export default CountdownTimer