UNPKG

vue3-countdown

Version:

A simple countdown component for Vue3.x.

123 lines (113 loc) 2.86 kB
import { defineComponent, PropType, ref, computed, h } from 'vue' import { resolveCountdown, formatCountdown } from '../utils' export default defineComponent({ name: 'Countdown', emits: ['change', 'finish'], props: { // Countdown time. ms time: { type: Number as PropType<number>, default: 0 }, format: { type: String as PropType<string>, default: 'HH:mm:ss' }, autoStart: { type: Boolean as PropType<boolean>, default: true } }, setup (props, { emit }) { const currentTime = ref(props.time) const resolved = ref(resolveCountdown(currentTime.value, props.format)) const inCountdown = ref(false) const config = { restTime: props.time, now: 0, timer: 0 } // computed const stepInterval = computed( () => /s/i.test(props.format) ? 30 : 1000 ) const formatted = computed( () => formatCountdown(resolved.value, props.format) ) // methods const start = () => { if (!inCountdown.value) { config.now = Date.now() config.restTime = currentTime.value window.clearInterval(config.timer) config.timer = window.setInterval(step, stepInterval.value) inCountdown.value = true } } const step = () => { const { restTime, now } = config const interval = Date.now() - now const target = restTime > interval ? restTime - interval : 0 const thisResolved = resolveCountdown(target, props.format) const thisFormatted = formatCountdown(thisResolved, props.format) if (thisFormatted !== formatted.value) { emit('change', { currentTime: target, resolved: thisResolved, formatted: thisFormatted }) resolved.value = thisResolved } currentTime.value = target if (restTime <= interval) { stop() } } const stop = () => { doStop() emit('finish') } const doStop = () => { inCountdown.value = false window.clearInterval(config.timer) } const reset = () => { currentTime.value = config.restTime = props.time resolved.value = resolveCountdown(props.time, props.format) doStop() } if (props.autoStart) { start() } return { currentTime, resolved, formatted, inCountdown, start, stop, reset } }, render () { const { currentTime, resolved, formatted } = this return h( 'div', null, ( this.$slots.default && this.$slots.default({ currentTime, resolved, formatted }) ) || this.formatted ) } })