返回 slidev
useTimer.ts
根目录 / packages / client / composables / useTimer.ts
1 import { parseTimeString } from '@slidev/parser/utils'
2 import { useInterval } from '@vueuse/core'
3 import { computed, toRef } from 'vue'
4 import { configs } from '../env'
5 import { sharedState } from '../state/shared'
6
7 export function useTimer() {
8 const mode = computed(() => configs.timer || 'stopwatch')
9 const duration = computed(() => parseTimeString(configs.duration).seconds)
10 const interval = useInterval(100, { controls: true })
11
12 const state = toRef(sharedState, 'timer')
13 const status = computed(() => state.value?.status)
14 const passedMs = computed(() => {
15 // eslint-disable-next-line ts/no-unused-expressions
16 interval.counter.value
17 if (state.value.status === 'stopped' || !state.value.startedAt)
18 return 0
19 if (state.value.status === 'paused')
20 return state.value.pausedAt - state.value.startedAt
21 return Date.now() - state.value.startedAt
22 })
23 const passed = computed(() => passedMs.value / 1000)
24 const percentage = computed(() => passed.value / duration.value * 100)
25
26 const timer = computed(() => {
27 if (mode.value === 'stopwatch') {
28 if (state.value.status === 'stopped' || !state.value.startedAt)
29 return { h: '', m: '-', s: '--', ms: '-' }
30 }
31
32 const total = mode.value === 'countdown'
33 ? duration.value * 1000 - passedMs.value
34 : passedMs.value
35
36 let h = Math.floor(total / 1000 / 60 / 60).toString()
37 if (h === '0')
38 h = ''
39 let min = Math.floor(total / 1000 / 60 % 60).toString()
40 if (h)
41 min = min.padStart(2, '0')
42 const sec = Math.floor(total / 1000 % 60).toString().padStart(2, '0')
43 const ms = Math.floor(total % 1000 / 100).toString()
44
45 return {
46 h,
47 m: min,
48 s: sec,
49 ms,
50 }
51 })
52
53 function reset() {
54 interval.pause()
55 state.value = {
56 status: 'stopped',
57 slides: {},
58 startedAt: 0,
59 pausedAt: 0,
60 }
61 }
62
63 function resume() {
64 if (!state.value)
65 return
66 if (state.value?.status === 'stopped') {
67 state.value.status = 'running'
68 state.value.startedAt = Date.now()
69 }
70 else if (state.value.status === 'paused') {
71 state.value.status = 'running'
72 state.value.startedAt = Date.now() - (state.value.pausedAt - state.value.startedAt)
73 }
74 interval.resume()
75 }
76
77 function pause() {
78 state.value.status = 'paused'
79 state.value.pausedAt = Date.now()
80 interval.pause()
81 }
82
83 function toggle() {
84 if (state.value.status === 'running') {
85 pause()
86 }
87 else {
88 resume()
89 }
90 }
91
92 return {
93 state,
94 status,
95 timer,
96 reset,
97 toggle,
98 resume,
99 pause,
100 passed,
101 percentage,
102 duration,
103 mode,
104 }
105 }
106
106 lines TYPESCRIPT