@@ -2,40 +2,59 @@ import { computed, onScopeDispose, ref } from 'vue';
22import { useRafFn } from '@vueuse/core' ;
33
44/**
5- * count down
5+ * A hook for implementing a countdown timer. It uses `requestAnimationFrame` for smooth and accurate timing,
6+ * independent of the screen refresh rate.
67 *
7- * @param seconds - count down seconds
8+ * @param initialSeconds - The total number of seconds for the countdown.
89 */
9- export default function useCountDown ( seconds : number ) {
10- const FPS_PER_SECOND = 60 ;
10+ export default function useCountDown ( initialSeconds : number ) {
11+ const remainingSeconds = ref ( 0 ) ;
1112
12- const fps = ref ( 0 ) ;
13+ const count = computed ( ( ) => Math . ceil ( remainingSeconds . value ) ) ;
1314
14- const count = computed ( ( ) => Math . ceil ( fps . value / FPS_PER_SECOND ) ) ;
15-
16- const isCounting = computed ( ( ) => fps . value > 0 ) ;
15+ const isCounting = computed ( ( ) => remainingSeconds . value > 0 ) ;
1716
1817 const { pause, resume } = useRafFn (
19- ( ) => {
20- if ( fps . value > 0 ) {
21- fps . value -= 1 ;
22- } else {
18+ ( { delta } ) => {
19+ // delta: milliseconds elapsed since the last frame.
20+
21+ // If countdown already reached zero or below, ensure it's 0 and stop.
22+ if ( remainingSeconds . value <= 0 ) {
23+ remainingSeconds . value = 0 ;
24+ pause ( ) ;
25+ return ;
26+ }
27+
28+ // Calculate seconds passed since the last frame.
29+ const secondsPassed = delta / 1000 ;
30+ remainingSeconds . value -= secondsPassed ;
31+
32+ // If countdown has finished after decrementing.
33+ if ( remainingSeconds . value <= 0 ) {
34+ remainingSeconds . value = 0 ;
2335 pause ( ) ;
2436 }
2537 } ,
26- { immediate : false }
38+ { immediate : false } // The timer does not start automatically.
2739 ) ;
2840
29- function start ( updateSeconds : number = seconds ) {
30- fps . value = FPS_PER_SECOND * updateSeconds ;
41+ /**
42+ * Starts the countdown.
43+ *
44+ * @param [updatedSeconds=initialSeconds] - Optionally, start with a new duration. Default is `initialSeconds`
45+ */
46+ function start ( updatedSeconds : number = initialSeconds ) {
47+ remainingSeconds . value = updatedSeconds ;
3148 resume ( ) ;
3249 }
3350
51+ /** Stops the countdown and resets the remaining time to 0. */
3452 function stop ( ) {
35- fps . value = 0 ;
53+ remainingSeconds . value = 0 ;
3654 pause ( ) ;
3755 }
3856
57+ // Ensure the rAF loop is cleaned up when the component is unmounted.
3958 onScopeDispose ( ( ) => {
4059 pause ( ) ;
4160 } ) ;
0 commit comments