From 7484512252a6551b0f977609a3c2ac9826c57bbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E7=BF=94?= Date: Thu, 23 Apr 2026 08:07:48 +0800 Subject: [PATCH] =?UTF-8?q?refactor(=E5=AF=BC=E8=88=AA):=20=E5=B0=86?= =?UTF-8?q?=E5=93=88=E5=B8=8C=E8=B7=AF=E7=94=B1=E6=94=B9=E4=B8=BA=E6=A0=87?= =?UTF-8?q?=E5=87=86=E8=B7=AF=E5=BE=84=E8=B7=AF=E7=94=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 重构导航系统,将原有的哈希路由(#section)改为标准路径路由(/path) 修改相关组件和测试用例以适应新的路由方式 移除不必要的滚动和哈希监听逻辑 --- src/components/layout/header.tsx | 99 ++----------------- src/components/layout/mobile-menu.tsx | 17 ++-- src/components/layout/mobile-tab-bar.test.tsx | 6 +- src/components/layout/mobile-tab-bar.tsx | 38 ++----- src/lib/constants/navigation.ts | 12 +-- 5 files changed, 32 insertions(+), 140 deletions(-) diff --git a/src/components/layout/header.tsx b/src/components/layout/header.tsx index ddcbaf1..b20f9e2 100644 --- a/src/components/layout/header.tsx +++ b/src/components/layout/header.tsx @@ -1,66 +1,24 @@ 'use client'; -import { Suspense, useState, useEffect, useCallback, useRef } from 'react'; +import { Suspense, useState, useEffect, useCallback } from 'react'; import { StaticLink } from '@/components/ui/static-link'; import Image from 'next/image'; -import { usePathname, useSearchParams } from 'next/navigation'; +import { usePathname } from 'next/navigation'; import { Menu, X } from 'lucide-react'; import { AnimatePresence, motion } from 'framer-motion'; import { Button } from '@/components/ui/button'; import { COMPANY_INFO, NAVIGATION, type NavigationItem } from '@/lib/constants'; import { useFocusTrap } from '@/hooks/use-focus-trap'; -declare global { - interface Window { - __isProgrammaticScroll?: boolean; - } -} - function HeaderContent() { const [isOpen, setIsOpen] = useState(false); const [isScrolled, setIsScrolled] = useState(false); const pathname = usePathname(); - const searchParams = useSearchParams(); const focusTrapRef = useFocusTrap(isOpen); - const isScrollingRef = useRef(false); - const scrollTimeoutRef = useRef(null); - - const getActiveSection = useCallback(() => { - if (pathname === '/contact') {return 'contact';} - if (pathname === '/') { - const section = searchParams.get('section'); - return section || 'home'; - } - return ''; - }, [pathname, searchParams]); - - const activeSection = getActiveSection(); useEffect(() => { const handleScroll = () => { setIsScrolled(window.scrollY > 20); - - if (pathname === '/' && !isScrollingRef.current && !window.__isProgrammaticScroll) { - const scrollPosition = window.scrollY + 100; - const sections = ['home', 'services', 'solutions', 'products', 'cases', 'about', 'team', 'news']; - - for (const sectionId of sections) { - const element = document.getElementById(sectionId); - if (element) { - const offsetTop = element.offsetTop; - const offsetHeight = element.offsetHeight; - - if (scrollPosition >= offsetTop && scrollPosition < offsetTop + offsetHeight) { - const currentSection = searchParams.get('section') || 'home'; - if (currentSection !== sectionId) { - const url = sectionId === 'home' ? '/' : `/?section=${sectionId}`; - window.history.replaceState(null, '', url); - } - break; - } - } - } - } }; const handleGlobalKeyDown = (e: KeyboardEvent) => { @@ -75,11 +33,8 @@ function HeaderContent() { return () => { window.removeEventListener('scroll', handleScroll); window.removeEventListener('keydown', handleGlobalKeyDown); - if (scrollTimeoutRef.current) { - clearTimeout(scrollTimeoutRef.current); - } }; - }, [pathname, isOpen, searchParams]); + }, [isOpen]); const handleKeyDown = useCallback((e: React.KeyboardEvent) => { if (e.key === 'Enter' || e.key === ' ') { @@ -93,57 +48,21 @@ function HeaderContent() { const handleNavClick = useCallback((e: React.MouseEvent, item: NavigationItem) => { e.preventDefault(); - - if (item.id === 'contact') { - window.location.href = '/contact'; - } else if (item.id === 'home') { - if (pathname === '/') { - isScrollingRef.current = true; - window.scrollTo({ top: 0, behavior: 'smooth' }); - window.history.pushState(null, '', '/'); - - scrollTimeoutRef.current = setTimeout(() => { - isScrollingRef.current = false; - }, 1000); - } else { - window.location.href = '/'; - } - } else { - if (pathname === '/') { - const scrollToSection = (retryCount = 0) => { - const element = document.getElementById(item.id); - if (element) { - isScrollingRef.current = true; - element.scrollIntoView({ behavior: 'smooth', block: 'start' }); - window.history.pushState(null, '', `/?section=${item.id}`); - - scrollTimeoutRef.current = setTimeout(() => { - isScrollingRef.current = false; - }, 1000); - } else if (retryCount < 10) { - setTimeout(() => scrollToSection(retryCount + 1), 100); - } - }; - scrollToSection(); - } else { - window.location.href = `/?section=${item.id}`; - } - } - + window.location.href = item.href; setIsOpen(false); - }, [pathname]); + }, []); const isActive = useCallback((item: NavigationItem) => { if (item.id === 'contact') { return pathname === '/contact'; } - if (pathname === '/') { - return activeSection === item.id; + if (item.id === 'home') { + return pathname === '/'; } - return false; - }, [pathname, activeSection]); + return pathname === `/${item.id}`; + }, [pathname]); const navigationItems = NAVIGATION; diff --git a/src/components/layout/mobile-menu.tsx b/src/components/layout/mobile-menu.tsx index f9a0296..cf50280 100644 --- a/src/components/layout/mobile-menu.tsx +++ b/src/components/layout/mobile-menu.tsx @@ -26,19 +26,16 @@ export function MobileMenu({ className }: MobileMenuProps) { }; }, [isOpen]); - const handleNavClick = (id: string) => { + const handleNavClick = (href: string) => { setIsOpen(false); - const element = document.getElementById(id); - if (element) { - element.scrollIntoView({ behavior: 'smooth' }); - } + window.location.href = href; }; - const handleKeyDown = (event: React.KeyboardEvent, id?: string) => { + const handleKeyDown = (event: React.KeyboardEvent, href?: string) => { if (event.key === 'Enter' || event.key === ' ') { event.preventDefault(); - if (id) { - handleNavClick(id); + if (href) { + handleNavClick(href); } else { setIsOpen(!isOpen); } @@ -84,8 +81,8 @@ export function MobileMenu({ className }: MobileMenuProps) { {NAVIGATION.map((item) => (