47 lines
1.3 KiB
JavaScript
47 lines
1.3 KiB
JavaScript
import {
|
|
useElementBounding,
|
|
useIntersectionObserver,
|
|
useWindowSize,
|
|
} from '@vueuse/core'
|
|
import { ref } from 'vue'
|
|
import { mapRange, clamp } from '@/libs/math'
|
|
import useLenis from '@/composables/useLenis'
|
|
|
|
const { height: wHeight } = useWindowSize()
|
|
|
|
export const useScrollProgress = (el, callback, entry = 0.5, exit = 0.5) => {
|
|
const isActive = ref(true)
|
|
const smoothProgress = ref(0)
|
|
|
|
const { height, top } = useElementBounding(el)
|
|
|
|
const isIntersected = ref(false)
|
|
const { stop } = useIntersectionObserver(el, ([{ isIntersecting }]) => {
|
|
isIntersected.value = isIntersecting
|
|
})
|
|
|
|
useLenis(({ scroll }) => {
|
|
if (!isActive.value) return
|
|
if (!height.value || !wHeight.value) return
|
|
if (!isIntersected.value) return
|
|
|
|
const pageTop = scroll + top.value
|
|
|
|
const start = pageTop - wHeight.value * entry
|
|
const end = pageTop + height.value - wHeight.value * exit
|
|
|
|
let rawProgress = mapRange(start, end, scroll, 0, 1)
|
|
rawProgress = clamp(0, rawProgress, 1)
|
|
|
|
smoothProgress.value += (rawProgress - smoothProgress.value) * 0.1
|
|
callback?.(smoothProgress.value)
|
|
})
|
|
|
|
const destroy = () => {
|
|
isActive.value = false
|
|
stop?.()
|
|
}
|
|
|
|
return { destroy }
|
|
}
|