49 lines
1.4 KiB
TypeScript
49 lines
1.4 KiB
TypeScript
"use client"
|
||
|
||
import { useState, useEffect, useRef, useCallback } from "react"
|
||
|
||
/**
|
||
* 监听滚动位置,返回 scrollY 值(被动监听,高性能)
|
||
*/
|
||
export function useScrollY() {
|
||
const [scrollY, setScrollY] = useState(0)
|
||
|
||
useEffect(() => {
|
||
const onScroll = () => setScrollY(window.scrollY)
|
||
window.addEventListener("scroll", onScroll, { passive: true })
|
||
return () => window.removeEventListener("scroll", onScroll)
|
||
}, [])
|
||
|
||
return scrollY
|
||
}
|
||
|
||
/**
|
||
* 对给定元素计算视差偏移量
|
||
* @param speed 视差倍率,0 = 无效果,0.5 = 半速(向上),负值反向
|
||
* @returns ref + translateY 字符串
|
||
*/
|
||
export function useParallax(speed: number = 0.4) {
|
||
const ref = useRef<HTMLDivElement>(null)
|
||
const [offset, setOffset] = useState(0)
|
||
|
||
const calculate = useCallback(() => {
|
||
if (!ref.current) return
|
||
const rect = ref.current.getBoundingClientRect()
|
||
const centerY = rect.top + rect.height / 2
|
||
const viewportCenter = window.innerHeight / 2
|
||
setOffset((centerY - viewportCenter) * speed)
|
||
}, [speed])
|
||
|
||
useEffect(() => {
|
||
calculate()
|
||
window.addEventListener("scroll", calculate, { passive: true })
|
||
window.addEventListener("resize", calculate, { passive: true })
|
||
return () => {
|
||
window.removeEventListener("scroll", calculate)
|
||
window.removeEventListener("resize", calculate)
|
||
}
|
||
}, [calculate])
|
||
|
||
return { ref, translateY: `${offset}px` }
|
||
}
|