完善页头样式

This commit is contained in:
2025-03-12 15:13:37 +08:00
parent 8ea085463e
commit e592137370

View File

@@ -1,59 +1,96 @@
'use client' 'use client'
import {ReactNode, useEffect, useState} from 'react' import {ReactNode, useCallback, useEffect, useMemo, useState} from 'react'
import Link from 'next/link' import Link from 'next/link'
import Wrap from '@/components/wrap' import Wrap from '@/components/wrap'
export type HeaderProps = {} export type HeaderProps = {}
export default function Header(props: HeaderProps) { export default function Header(props: HeaderProps) {
const [isScrolled, setIsScrolled] = useState(window.scrollY > 48)
const handleScroll = () => { // ======================
setIsScrolled(window.scrollY > 48) // 滚动条状态
} // ======================
const [scroll, setScroll] = useState(window.scrollY > 48)
const handleScroll = useCallback(() => {
setScroll(window.scrollY > 48)
}, [])
useEffect(() => { useEffect(() => {
window.addEventListener('scroll', handleScroll) window.addEventListener('scroll', handleScroll)
return () => { return () => {
window.removeEventListener('scroll', handleScroll) window.removeEventListener('scroll', handleScroll)
} }
}, []) }, [handleScroll])
// ======================
// 菜单状态
// ======================
const [menu, setMenu] = useState<string>('')
// ======================
// 覆盖状态
// ======================
const [overlay, setOverlay] = useState(false)
useEffect(() => {
setOverlay(scroll || menu !== '')
}, [menu, scroll])
// ======================
// 渲染组件
// ======================
return ( return (
<header <header
className={[ className={[
`w-full h-24 max-md:h-16 overflow-hidden fixed top-0 shadow-lg`, `fixed top-0 w-full`,
`transition-shadow duration-200 ${isScrolled ? 'bg-[rgba(255,255,255,0.9)] backdrop-blur-sm' : 'bg-transparent shadow-transparent'}`, `transition-all duration-200 ${overlay ? `bg-[#fffe] shadow-lg backdrop-blur-sm` : 'bg-transparent shadow-transparent'}`,
].join(' ')}> ].join(' ')}>
<Wrap className="flex h-full items-center justify-between"> <Wrap className=" h-20 max-md:h-16 flex justify-between">
<div className="flex justify-between gap-8">
<div className="flex items-center justify-between gap-8">
{/* logo */} {/* logo */}
<Link href="/"> <Link href="/" className={`flex items-center`}>
<img src={`/logo.svg`} alt={`logo`} className={`w-16 max-md:w-12 h-16 max-md:h-12 rounded-full bg-gray-100`}/> <img src={`/logo.svg`} alt={`logo`} className={`w-16 max-md:w-12 h-16 max-md:h-12 rounded-full bg-gray-100`}/>
</Link> </Link>
{/* 菜单 */} {/* 菜单 */}
<nav className={`flex items-center max-lg:hidden`}> <nav>
<ul className="flex items-center text-xl"> <ul className="h-full flex items-center text-xl max-lg:hidden">
<NavItemTop> <NavItemTop>
<Link href={`/`}></Link> <Link href={`/`}></Link>
</NavItemTop> </NavItemTop>
<NavItemTop>
<button></button> <NavItemTop
onEnter={() => setMenu('product')}
onLeave={() => setMenu('')}
>
<button className={`cursor-pointer`}></button>
<SvgDown/> <SvgDown/>
</NavItemTop> </NavItemTop>
<NavItemTop>
<button></button> <NavItemTop
onEnter={() => setMenu('solution')}
onLeave={() => setMenu('')}
>
<button className={`cursor-pointer`}></button>
<SvgDown/> <SvgDown/>
</NavItemTop> </NavItemTop>
<NavItemTop>
<button></button> <NavItemTop
onEnter={() => setMenu('help')}
onLeave={() => setMenu('')}
>
<button className={`cursor-pointer`}></button>
<SvgDown/> <SvgDown/>
</NavItemTop> </NavItemTop>
<NavItemTop> <NavItemTop>
<Link href={`#`}></Link> <Link href={`#`}></Link>
</NavItemTop> </NavItemTop>
<NavItemTop> <NavItemTop>
<Link href={`#`}>广</Link> <Link href={`#`}>广</Link>
</NavItemTop> </NavItemTop>
@@ -74,17 +111,34 @@ export default function Header(props: HeaderProps) {
</a> </a>
</div> </div>
</Wrap> </Wrap>
{/* 下拉菜单 */}
<div
className={[
`transition-[visibility,opacity,height] duration-200 ease-in-out`,
`${menu === ''
? 'delay-[200ms,0s,0s] invisible opacity-0 h-0 pointer-events-none'
: 'delay-[0s,0s,0s] visible opacity-100 h-80'
}`,
].join(' ')}>
</div>
{{
'product': <ProductMenu/>,
'solution': <SolutionMenu/>,
'help': <HelpMenu/>,
}[menu]}
Using a wrapper div to handle transitions
</header> </header>
) )
} }
type NavItemTopProps = { function NavItemTop(props: {
children: ReactNode children: ReactNode
} onEnter?: () => void
onLeave?: () => void
function NavItemTop(props: NavItemTopProps) { }) {
return ( return (
<li className={`px-4 h-10 flex items-center text-xl`}> <li className={`h-10 px-4 flex items-center text-xl cursor-pointer`} onPointerEnter={props.onEnter} onPointerLeave={props.onLeave}>
{props.children} {props.children}
</li> </li>
) )
@@ -99,3 +153,41 @@ function SvgDown() {
</svg> </svg>
) )
} }
function ProductMenu() {
const [type, setType] = useState<'domestic' | 'oversea'>('domestic')
return (
<div className={`flex`}>
<ul role={`tablist`}>
<li role={`tab`}>
<button onClick={() => setType('domestic')}>
</button>
</li>
<li role={`tab`}>
<button onClick={() => setType('oversea')}>
</button>
</li>
</ul>
<section role={`tabpanel`}>
{{
'domestic': <div></div>,
'oversea': <div></div>,
}[type]}
</section>
</div>
)
}
function SolutionMenu() {
return (
<div></div>
)
}
function HelpMenu() {
return (
<div></div>
)
}