From d6e87dfafed05862cba37d1a4d37533a6161f8b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E7=BF=94?= Date: Mon, 23 Feb 2026 08:26:03 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=AF=BC=E8=88=AA?= =?UTF-8?q?=E6=A0=8F=E7=82=B9=E5=87=BB=E5=90=8E=20active=20=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E8=A2=AB=E6=BB=9A=E5=8A=A8=E8=A6=86=E7=9B=96=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 isScrollingRef 标记,在点击导航后阻止滚动监听器更新 activeSection - 改进 section 检测逻辑,使用 sectionTop 和 sectionBottom 精确判断 - 点击导航后 1 秒内不响应滚动检测,确保平滑滚动完成 --- src/components/layout/header.tsx | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/src/components/layout/header.tsx b/src/components/layout/header.tsx index c03bd92..4bea0f3 100644 --- a/src/components/layout/header.tsx +++ b/src/components/layout/header.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useState, useEffect, useCallback } from 'react'; +import { useState, useEffect, useCallback, useRef } from 'react'; import { Menu, X } from 'lucide-react'; import { motion, AnimatePresence } from 'framer-motion'; import { Button } from '@/components/ui/button'; @@ -10,6 +10,8 @@ export function Header() { const [isOpen, setIsOpen] = useState(false); const [activeSection, setActiveSection] = useState('home'); const [isScrolled, setIsScrolled] = useState(false); + const isScrollingRef = useRef(false); + const scrollTimeoutRef = useRef(null); const handleNavClick = useCallback((e: React.MouseEvent, href: string) => { e.preventDefault(); @@ -17,6 +19,12 @@ export function Header() { const element = document.getElementById(targetId); if (element) { + isScrollingRef.current = true; + + if (scrollTimeoutRef.current) { + clearTimeout(scrollTimeoutRef.current); + } + const headerOffset = 64; const elementPosition = element.getBoundingClientRect().top; const offsetPosition = elementPosition + window.pageYOffset - headerOffset; @@ -28,6 +36,10 @@ export function Header() { setActiveSection(targetId); setIsOpen(false); + + scrollTimeoutRef.current = setTimeout(() => { + isScrollingRef.current = false; + }, 1000); } }, []); @@ -35,6 +47,10 @@ export function Header() { const handleScroll = () => { setIsScrolled(window.scrollY > 20); + if (isScrollingRef.current) { + return; + } + const sections = NAVIGATION.map(item => item.href.replace('#', '')); const scrollPosition = window.scrollY + 100; @@ -42,7 +58,8 @@ export function Header() { const section = document.getElementById(sections[i]); if (section) { const sectionTop = section.offsetTop; - if (scrollPosition >= sectionTop) { + const sectionBottom = sectionTop + section.offsetHeight; + if (scrollPosition >= sectionTop && scrollPosition < sectionBottom) { setActiveSection(sections[i]); break; } @@ -53,7 +70,12 @@ export function Header() { window.addEventListener('scroll', handleScroll, { passive: true }); handleScroll(); - return () => window.removeEventListener('scroll', handleScroll); + return () => { + window.removeEventListener('scroll', handleScroll); + if (scrollTimeoutRef.current) { + clearTimeout(scrollTimeoutRef.current); + } + }; }, []); return ( @@ -113,7 +135,7 @@ export function Header() {