页面初始渲染后平滑滚动定位异常的修复方法咨询
修复react-scroll Link组件首次平滑滚动定位偏移问题
页面加载/更新后首次点击react-scroll的Link组件,平滑滚动位置偏下;手动滚动或二次点击后恢复正常;关闭
smooth属性则首次定位正常。
方案1:动态计算偏移量(解决布局未稳定导致的固定offset误差)
首次加载时页面布局可能未完全稳定(比如导航栏高度由异步内容决定),固定的offset=-130会出现偏差。改为动态获取目标元素或导航栏的实际高度来计算偏移:
"use client"; import React, { useState, useEffect } from "react"; import { Link } from "react-scroll"; interface ButtonNavigationProps { navigateTo: string; children: React.ReactNode; } const ButtonNavigation: React.FC<ButtonNavigationProps> = ({ navigateTo, children, }) => { const [offset, setOffset] = useState(-130); useEffect(() => { // 假设导航栏的id是"navbar",动态获取其高度 const navbar = document.getElementById("navbar"); if (navbar) { setOffset(-navbar.offsetHeight); } // 监听窗口 resize,更新偏移量 const handleResize = () => { if (navbar) setOffset(-navbar.offsetHeight); }; window.addEventListener("resize", handleResize); return () => window.removeEventListener("resize", handleResize); }, []); return ( <Link smooth={true} spy={true} isDynamic={true} to={navigateTo} offset={offset} duration={650} className="flex items-center gap-x-2 px-8 py-3" > {children} <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24" fill="currentColor" > <path d="m560-240-56-58 142-142H160v-80h486L504-662l56-58 240 240-240 240Z" /> </svg> </Link> ); }; export default ButtonNavigation;
方案2:禁用isDynamic并手动刷新滚动计算
isDynamic属性可能在首次加载时干扰元素位置检测,关闭后配合组件挂载时刷新scroll实例:
"use client"; import React, { useEffect } from "react"; import { Link, scroller } from "react-scroll"; interface ButtonNavigationProps { navigateTo: string; children: React.ReactNode; } const ButtonNavigation: React.FC<ButtonNavigationProps> = ({ navigateTo, children, }) => { useEffect(() => { // 组件挂载后刷新scroll的位置计算 scroller.refresh(); }, []); return ( <Link smooth={true} spy={true} isDynamic={false} // 禁用动态检测 to={navigateTo} offset={-130} duration={650} className="flex items-center gap-x-2 px-8 py-3" > {children} <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24" fill="currentColor" > <path d="m560-240-56-58 142-142H160v-80h486L504-662l56-58 240 240-240 240Z" /> </svg> </Link> ); }; export default ButtonNavigation;
方案3:替换为原生平滑滚动(绕过react-scroll的bug)
如果以上方案无效,直接使用浏览器原生的scrollIntoView实现平滑滚动,避免依赖react-scroll的内部逻辑:
"use client"; import React from "react"; interface ButtonNavigationProps { navigateTo: string; children: React.ReactNode; } const ButtonNavigation: React.FC<ButtonNavigationProps> = ({ navigateTo, children, }) => { const handleScroll = () => { const target = document.getElementById(navigateTo); if (target) { // 手动计算偏移量 const navbarHeight = document.getElementById("navbar")?.offsetHeight || 130; const targetTop = target.getBoundingClientRect().top + window.scrollY - navbarHeight; window.scrollTo({ top: targetTop, behavior: "smooth", }); } }; return ( <button onClick={handleScroll} className="flex items-center gap-x-2 px-8 py-3" > {children} <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24" fill="currentColor" > <path d="m560-240-56-58 142-142H160v-80h486L504-662l56-58 240 240-240 240Z" /> </svg> </button> ); }; export default ButtonNavigation;
方案4:延迟初始化spy属性
首次加载时不启用spy,等待页面稳定后再开启:
"use client"; import React, { useState, useEffect } from "react"; import { Link } from "react-scroll"; interface ButtonNavigationProps { navigateTo: string; children: React.ReactNode; } const ButtonNavigation: React.FC<ButtonNavigationProps> = ({ navigateTo, children, }) => { const [enableSpy, setEnableSpy] = useState(false); useEffect(() => { // 延迟100ms启用spy,等待布局稳定 const timer = setTimeout(() => setEnableSpy(true), 100); return () => clearTimeout(timer); }, []); return ( <Link smooth={true} spy={enableSpy} isDynamic={true} to={navigateTo} offset={-130} duration={650} className="flex items-center gap-x-2 px-8 py-3" > {children} <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24" fill="currentColor" > <path d="m560-240-56-58 142-142H160v-80h486L504-662l56-58 240 240-240 240Z" /> </svg> </Link> ); }; export default ButtonNavigation;
内容的提问来源于stack exchange,提问作者kantemyr
相关产品推荐
相关产品推荐

