点击GSAP动画中的React Router Link致网站崩溃求助
问题
我用GSAP给项目板块实现了横向滚动动画,但遇到了问题:点击正在执行GSAP动画的项目时,作品集网站崩溃。React Router的Link标签已经切换了URL,但路由配置的组件未渲染,页面呈空白状态。我使用了LocomotiveScroll,并通过自定义Hook使其兼容GSAP的ScrollTrigger。怀疑是路由切换时LocomotiveScroll保留了新页面不存在的滚动位置导致的问题,控制台无报错,求解决建议。
相关代码
项目链接组件代码
<Link to={`/projects/${project.id}`} className={styles.link} id='link' > <div id='projectImageContainer' className={styles.projectImageContainer} onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)} > {/* <AnimatedImage src={project.image} playAnim={hover} /> */} </div> </Link>
GSAP横向滚动动画代码
useEffect(() => { gsap.registerPlugin(ScrollTrigger); const scrollContext = gsap.context(() => { scrollTl.current = gsap.timeline({ scrollTrigger: { trigger: projectsContainerRef.current, scroller: '.App', start: 'top top', end: `+=${trackRef.current.offsetWidth}`, pin: true, scrub: 0.5, }, }); scrollTl.current .to(trackRef.current, { xPercent: -100, ease: 'none', }) .to( titleRef.current, { xPercent: -50, ease: 'none', }, '<' ); }); return () => scrollContext.revert(); }, []);
解决建议
路由切换前清理GSAP与ScrollTrigger实例:在组件卸载或路由跳转时,除了调用
scrollContext.revert(),还要手动销毁所有ScrollTrigger实例,同时终止GSAP时间线:// 在组件卸载的清理函数或路由跳转事件中执行 scrollTl.current?.kill(); ScrollTrigger.getAll().forEach(trigger => trigger.kill());残留的动画实例会尝试操作已卸载的DOM元素,引发静默异常导致页面崩溃。
重置LocomotiveScroll滚动位置:通过React Router的
useLocation监听路由变化,在新页面挂载时调用LocomotiveScroll的scrollTo(0)方法,强制回到页面顶部,避免旧页面的滚动偏移量被带到新页面:import { useLocation } from 'react-router-dom'; import locomotiveScroll from '../path/to/your/locomotive/instance'; useEffect(() => { locomotiveScroll.scrollTo(0, { immediate: true }); }, [location.pathname]);点击Link时暂停动画:给Link添加
onClick事件,先暂停当前GSAP动画再执行路由跳转,避免动画在DOM切换过程中仍在操作元素:<Link to={`/projects/${project.id}`} className={styles.link} id='link' onClick={() => scrollTl.current?.pause()} > {/* 子元素 */} </Link>检查ScrollTrigger的scroller配置:当前ScrollTrigger使用
.App作为scroller,若路由切换后该容器的结构或存在状态发生变化,会导致ScrollTrigger失效。可将scroller替换为更稳定的根容器,或在路由切换时重新初始化ScrollTrigger。监听路由变化清理动画上下文:在项目列表组件中,通过
useLocation监听路径变化,当路径离开项目列表页时,彻底清理GSAP上下文和相关实例:import { useLocation } from 'react-router-dom'; useEffect(() => { const scrollContext = gsap.context(() => { // 初始化动画逻辑 }); const cleanup = () => { scrollContext.revert(); scrollTl.current?.kill(); ScrollTrigger.getAll().forEach(trigger => trigger.kill()); }; return cleanup; }, [location.pathname]);
内容的提问来源于stack exchange,提问作者Oliver

