| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768 |
- import { computed, onScopeDispose, ref } from 'vue';
- import { useRafFn } from '@vueuse/core';
- /**
- * A hook for implementing a countdown timer. It uses `requestAnimationFrame` for smooth and accurate timing,
- * independent of the screen refresh rate.
- *
- * @param initialSeconds - The total number of seconds for the countdown.
- */
- export default function useCountDown(initialSeconds: number) {
- const remainingSeconds = ref(0);
- const count = computed(() => Math.ceil(remainingSeconds.value));
- const isCounting = computed(() => remainingSeconds.value > 0);
- const { pause, resume } = useRafFn(
- ({ delta }) => {
- // delta: milliseconds elapsed since the last frame.
- // If countdown already reached zero or below, ensure it's 0 and stop.
- if (remainingSeconds.value <= 0) {
- remainingSeconds.value = 0;
- pause();
- return;
- }
- // Calculate seconds passed since the last frame.
- const secondsPassed = delta / 1000;
- remainingSeconds.value -= secondsPassed;
- // If countdown has finished after decrementing.
- if (remainingSeconds.value <= 0) {
- remainingSeconds.value = 0;
- pause();
- }
- },
- { immediate: false } // The timer does not start automatically.
- );
- /**
- * Starts the countdown.
- *
- * @param [updatedSeconds=initialSeconds] - Optionally, start with a new duration. Default is `initialSeconds`
- */
- function start(updatedSeconds: number = initialSeconds) {
- remainingSeconds.value = updatedSeconds;
- resume();
- }
- /** Stops the countdown and resets the remaining time to 0. */
- function stop() {
- remainingSeconds.value = 0;
- pause();
- }
- // Ensure the rAF loop is cleaned up when the component is unmounted.
- onScopeDispose(() => {
- pause();
- });
- return {
- count,
- isCounting,
- start,
- stop
- };
- }
|