38 lines
869 B
JavaScript
38 lines
869 B
JavaScript
|
|
import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
||
|
|
|
||
|
|
export function useAnimationProgress(deps = [], duration = 1100) {
|
||
|
|
const progress = ref(0)
|
||
|
|
let frameId = 0
|
||
|
|
|
||
|
|
const easeOutCubic = (value) => 1 - Math.pow(1 - value, 3)
|
||
|
|
|
||
|
|
function start() {
|
||
|
|
cancelAnimationFrame(frameId)
|
||
|
|
|
||
|
|
if (window.matchMedia?.('(prefers-reduced-motion: reduce)').matches) {
|
||
|
|
progress.value = 1
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
const startedAt = performance.now()
|
||
|
|
progress.value = 0
|
||
|
|
|
||
|
|
function tick(now) {
|
||
|
|
const elapsed = Math.min((now - startedAt) / duration, 1)
|
||
|
|
progress.value = easeOutCubic(elapsed)
|
||
|
|
if (elapsed < 1) frameId = requestAnimationFrame(tick)
|
||
|
|
}
|
||
|
|
|
||
|
|
frameId = requestAnimationFrame(tick)
|
||
|
|
}
|
||
|
|
|
||
|
|
onMounted(start)
|
||
|
|
onBeforeUnmount(() => cancelAnimationFrame(frameId))
|
||
|
|
|
||
|
|
if (deps.length) {
|
||
|
|
watch(deps, start)
|
||
|
|
}
|
||
|
|
|
||
|
|
return progress
|
||
|
|
}
|