"use client"; import { useEffect, useRef } from "react"; import gsap from "gsap"; import { ScrollTrigger } from "gsap/ScrollTrigger"; gsap.registerPlugin(ScrollTrigger); /** * GSAP 动画的统一入口。 * * 核心原则: * 1. 尊重 prefers-reduced-motion —— 开启时直接跳过动画,内容保持可见。 * 2. 在 gsap.context 内执行,卸载时自动 revert,避免泄露。 * * 用法: * const ref = useGsapAnimation((scope, isReduced) => { * if (isReduced) return; * gsap.from(".item", { y: 40, opacity: 0, stagger: 0.1, scrollTrigger: {...} }); * }); */ export function useGsapAnimation( setup: (scope: T, isReduced: boolean) => void, deps: unknown[] = [] ) { const ref = useRef(null); useEffect(() => { const el = ref.current; if (!el) return; const isReduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches; const ctx = gsap.context(() => setup(el, isReduced), el); return () => ctx.revert(); // eslint-disable-next-line react-hooks/exhaustive-deps }, deps); return ref; }