You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js中window.scrollTo跳转ID功能失效问题求助

Next.js锚点滚动自定义间距问题修复

问题根源

  1. 滚动目标位置错误:你计算了scrollPosition但在window.scrollTo里误用了headerHeight作为top值;同时getBoundingClientRect().top是元素相对视口的距离,需要加上当前滚动距离window.scrollY才能得到相对于文档顶部的正确位置。
  2. Link默认行为冲突:Next.js的Link组件点击会触发原生锚点跳转,直接覆盖你自定义的滚动逻辑。
  3. Ref创建方式不当:函数组件中用React.createRef()会在每次渲染时生成新的ref,应该用useRef()保证ref稳定。
  4. 未处理元素不存在的情况:如果navHeader不存在,offsetHeight会导致报错。

修复后的代码

'use client'
import Link from "next/link";
import React, { useRef } from "react";

export default function Scroll() {
    // 用useRef包裹ref数组,确保每个ref在组件生命周期内稳定
    const refs = useRef(Array.from({ length: 8 }, () => React.createRef<HTMLDivElement>()));

    const handleClick = (e: React.MouseEvent, index: number) => {
        // 阻止Link的默认锚点跳转行为,避免覆盖自定义滚动逻辑
        e.preventDefault();
        const ref = refs.current[index];
        if (ref.current) {
            const distanceToTop = ref.current.getBoundingClientRect().top;
            const margin = 20;
            // 处理header不存在的容错情况
            const header = document.getElementById('navHeader');
            const headerHeight = header ? header.offsetHeight : 0;
            // 计算正确的滚动位置:当前滚动距离 + 元素相对视口距离 - 头部高度 - 自定义间距
            const scrollPosition = window.scrollY + distanceToTop - headerHeight - margin;
            
            window.scrollTo({
                top: scrollPosition,
                behavior: 'smooth'
            });
        }
    };

    return (
        <>
            <div className="flex w-screen" id="section">
                <section className="sidebar max-w-md w-full relative">
                    <ul className={`flex flex-col items-center p-7 `}>
                        {refs.current.map((ref, index) => (
                            <li key={index}>
                                <Link href={`#${index + 1}`}>
                                    {/* 传递事件对象用于阻止默认行为 */}
                                    <button onClick={(e) => handleClick(e, index)}>My {index + 1} section</button>
                                </Link>
                            </li>
                        ))}
                    </ul>
                </section>
                <section className="content flex flex-col w-full " id="section" >
                    {refs.current.map((ref, index) => (
                        <div ref={ref} id={`${index + 1}`} className={`bg-slate-600 h-52 `} key={index}>SECTION {index + 1}</div>
                    ))}
                </section>
            </div>
            <div>
                <footer className="h-96 bg-fuchsia-200">
                    footer
                </footer>
            </div>
        </>
    );
}

关键修改说明

  • 改用useRef存储ref数组,避免每次渲染生成新ref导致关联失效。
  • 新增e.preventDefault()阻止Link组件的默认锚点跳转,确保自定义滚动逻辑生效。
  • 修正滚动位置计算公式,得到文档顶部的绝对滚动坐标。
  • 增加头部元素不存在的容错处理,避免运行时报错。

内容的提问来源于stack exchange,提问作者Prashant Rao

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 20:44:51