React滚轮导航:可滚动页面不触发,无滚动时跳转下一页
解决React布局中滚轮触发页面跳转的判断问题
你遇到的核心问题是wheel事件触发时机早于scroll事件,导致没法通过scrolling变量判断这次滚轮操作是否真的会让页面滚动。不用依赖scroll事件,直接在wheel事件里计算容器的滚动状态就行。
修改后的代码
function Layout({error}: Props) { const {pathname} = useLocation(); const {data: user, isLoading} = useUser(); const navigate = useNavigate(); const parent = useRef<HTMLDivElement>(null); useEffect(() => { const parentDiv = parent.current; if (!parentDiv) return; const handleWheel = (e: WheelEvent) => { const { scrollTop, scrollHeight, clientHeight } = parentDiv; // 判断是否滚到顶部且向上滚动 const isAtTop = scrollTop === 0 && e.deltaY < 0; // 判断是否滚到底部且向下滚动 const isAtBottom = scrollTop + clientHeight >= scrollHeight - 1 && e.deltaY > 0; if (isAtTop || isAtBottom) { // 阻止默认滚动行为(因为已经滚不动了) e.preventDefault(); // 这里可以根据需要调整跳转逻辑,比如按路由顺序跳转 const nextPath = getNextPath(pathname); if (nextPath) { navigate(nextPath); } } }; parentDiv.addEventListener("wheel", handleWheel, { passive: false }); return () => { parentDiv.removeEventListener("wheel", handleWheel); }; }, [pathname, navigate]) // 自定义路由跳转顺序,替换成你的实际路由列表 const getNextPath = (currentPath: string) => { const routes = ["/dashboard", "/page1", "/page2", "/page3"]; const currentIndex = routes.findIndex(path => path === currentPath); if (currentIndex === -1 || currentIndex === routes.length - 1) { return null; // 可以改成返回第一个路由实现循环跳转 } return routes[currentIndex + 1]; } console.log("loading layout"); const loadView = () => { if (error) return <ErrorPage />; if (pathname === "/dashboard") { if(isLoading) return <Box display="flex" justifyContent="center" width="100%" height="100%" alignItems="center"><CircularProgress /></Box> if(user?.username) return <DashboardPage /> return <ErrorPage /> } return <Outlet />; } return ( <ThemeProvider theme={darkTheme}> <CssBaseline /> <div ref={parent} id="wheeler" style={{width:"100vw", height: "100vh", overflowY: "auto"}}> <NavBar /> <Stack direction="row" sx={{width: "100vw", height: PAGE_HEIGHT}}> <Box sx={{display: {sm: "flex", xs: "none"}}}> <SocialMedia /> </Box> {loadView()} </Stack> </div> </ThemeProvider> ); } export default Layout;
关键说明
- 直接判断滚动边界:在
wheel事件里直接获取容器的scrollTop、scrollHeight和clientHeight,结合滚轮方向(deltaY正负)判断是否已经滚到顶部/底部,无需等待滞后的scroll事件。 - 阻止默认行为:当确定容器无法继续滚动时,调用
e.preventDefault()避免页面出现无效滚动的抖动。 - 自定义路由逻辑:通过
getNextPath函数控制页面跳转顺序,你可以根据实际路由列表调整,比如支持循环跳转、指定特定页面的下一页等。 - 清理事件监听:在
useEffect的返回函数中移除事件监听,避免组件卸载后出现内存泄漏。
内容的提问来源于stack exchange,提问作者Chrishdev
相关产品推荐
相关产品推荐

