React结合Lenis平滑滚动时页面切换无法回到顶部的问题
问题解决:Lenis平滑滚动下页面跳转时回到顶部失效的修复
问题根源
Lenis会接管原生滚动行为,直接调用window.scrollTo(0,0)无法被Lenis的滚动控制系统识别,尤其是在平滑滚动过程中跳转页面时,Lenis的滚动状态未重置,导致回到顶部功能失效。
解决方案
利用Lenis官方提供的scrollToAPI来控制滚动,替代原生方法,同时在路径变化时重置Lenis的滚动状态。
方案1:通过全局变量传递Lenis实例(快速实现)
1. 修改App.js初始化Lenis
import Lenis from '@studio-freight/lenis'; import { useEffect } from 'react'; import ScrollToTop from './ScrollToTop'; import { BrowserRouter } from 'react-router-dom'; function App() { useEffect(() => { const lenis = new Lenis(); function raf(time) { lenis.raf(time); requestAnimationFrame(raf); } requestAnimationFrame(raf); // 将Lenis实例挂载到window全局 window.lenis = lenis; return () => { lenis.destroy(); delete window.lenis; }; }, []); return ( <BrowserRouter> <ScrollToTop /> {/* 你的路由组件 */} </BrowserRouter> ); } export default App;
2. 更新ScrollToTop组件
import { useEffect } from "react"; import { useLocation } from "react-router-dom"; import { colors } from "./constants"; export default function ScrollToTop() { const { pathname } = useLocation(); useEffect(() => { if (window.lenis) { // 暂停当前平滑滚动,避免冲突 window.lenis.stop(); // 立即跳转到顶部,跳过平滑动画 window.lenis.scrollTo(0, { immediate: true }); // 重新启动Lenis滚动监听 window.lenis.start(); } else { // 降级处理:无Lenis时使用原生方法 window.scrollTo(0, 0); } document.body.style.backgroundColor = colors.white; }, [pathname]); return null; }
方案2:使用React Context传递Lenis实例(最佳实践)
1. 创建LenisContext.js
import { createContext, useContext, useEffect, useRef } from 'react'; import Lenis from '@studio-freight/lenis'; const LenisContext = createContext(null); export function LenisProvider({ children }) { const lenisRef = useRef(null); useEffect(() => { const lenis = new Lenis(); function raf(time) { lenis.raf(time); requestAnimationFrame(raf); } requestAnimationFrame(raf); lenisRef.current = lenis; return () => { lenis.destroy(); lenisRef.current = null; }; }, []); return ( <LenisContext.Provider value={lenisRef.current}> {children} </LenisContext.Provider> ); } export function useLenis() { return useContext(LenisContext); }
2. 修改App.js使用LenisProvider
import { LenisProvider } from './LenisContext'; import { BrowserRouter } from 'react-router-dom'; import ScrollToTop from './ScrollToTop'; function App() { return ( <LenisProvider> <BrowserRouter> <ScrollToTop /> {/* 你的路由组件 */} </BrowserRouter> </LenisProvider> ); } export default App;
3. 更新ScrollToTop组件
import { useEffect } from "react"; import { useLocation } from "react-router-dom"; import { useLenis } from "./LenisContext"; import { colors } from "./constants"; export default function ScrollToTop() { const { pathname } = useLocation(); const lenis = useLenis(); useEffect(() => { if (lenis) { lenis.stop(); lenis.scrollTo(0, { immediate: true }); lenis.start(); } else { window.scrollTo(0, 0); } document.body.style.backgroundColor = colors.white; }, [pathname, lenis]); return null; }
关键说明
immediate: true参数确保页面跳转时直接回到顶部,跳过平滑动画,符合页面切换的用户预期。- 每次路径变化时先暂停Lenis滚动,避免新旧页面的滚动状态冲突,完成跳转后再重启监听。
- 组件卸载时务必销毁Lenis实例,避免内存泄漏。
内容的提问来源于stack exchange,提问作者MattUribb
相关产品推荐
相关产品推荐

