449010718e
- 新增导航菜单数据配置 - 实现左侧logo和标题区域 - 添加中间导航链接区域 - 添加右侧菜单图标 - 优化header布局为flex响应式设计
141 lines
4.5 KiB
Vue
141 lines
4.5 KiB
Vue
<script setup lang="ts">
|
||
import { onBeforeUnmount, onMounted, ref } from 'vue'
|
||
import gsap from 'gsap'
|
||
import { ScrollTrigger } from 'gsap/ScrollTrigger'
|
||
|
||
gsap.registerPlugin(ScrollTrigger)
|
||
|
||
// 导航菜单数据配置
|
||
const navItems = [
|
||
{ name: 'Home', path: '/' },
|
||
{ name: 'Studio', path: '/studio' },
|
||
{ name: 'Work', path: '/work' },
|
||
{ name: 'News', path: '/news' },
|
||
{ name: 'Contact', path: '/contact' }
|
||
]
|
||
|
||
const topHeaderRef = ref<HTMLElement | null>(null)
|
||
const bottomHeaderRef = ref<HTMLElement | null>(null)
|
||
let topHeaderTween: gsap.core.Tween | null = null
|
||
let bottomHeaderScrollTrigger: ReturnType<typeof ScrollTrigger.create> | null = null
|
||
let isBottomHeaderVisible = false
|
||
|
||
const setBottomHeaderVisible = (visible: boolean) => {
|
||
if (!bottomHeaderRef.value || isBottomHeaderVisible === visible) {
|
||
return
|
||
}
|
||
|
||
isBottomHeaderVisible = visible
|
||
|
||
gsap.to(bottomHeaderRef.value, {
|
||
yPercent: visible ? 0 : 140,
|
||
autoAlpha: visible ? 1 : 0,
|
||
duration: 0.35,
|
||
ease: 'power2.out',
|
||
overwrite: 'auto',
|
||
})
|
||
}
|
||
|
||
onMounted(() => {
|
||
// 底部导航默认藏在视口下方,只有滚动到深处并向上滚时才出现。
|
||
gsap.set(bottomHeaderRef.value, {
|
||
yPercent: 140,
|
||
autoAlpha: 0,
|
||
})
|
||
|
||
// 顶部导航在页面刚开始滚动的前 200px 内逐渐上移并隐藏。
|
||
topHeaderTween = gsap.to(topHeaderRef.value, {
|
||
yPercent: -140,
|
||
autoAlpha: 0,
|
||
ease: 'none',
|
||
scrollTrigger: {
|
||
start: 0,
|
||
end: 200,
|
||
scrub: true,
|
||
},
|
||
})
|
||
|
||
bottomHeaderScrollTrigger = ScrollTrigger.create({
|
||
start: 0,
|
||
end: 'max',
|
||
onUpdate: (self) => {
|
||
const scrollY = self.scroll()
|
||
|
||
// 深度超过 2500px 后向上滚,显示未来用于深层内容的底部导航。
|
||
if (scrollY > 2500 && self.direction === -1) {
|
||
setBottomHeaderVisible(true)
|
||
return
|
||
}
|
||
|
||
// 回到 2300px 以内,或继续向下滚时,底部导航收回。
|
||
if (scrollY <= 2300 || self.direction === 1) {
|
||
setBottomHeaderVisible(false)
|
||
}
|
||
},
|
||
})
|
||
|
||
ScrollTrigger.refresh()
|
||
})
|
||
|
||
onBeforeUnmount(() => {
|
||
topHeaderTween?.scrollTrigger?.kill()
|
||
topHeaderTween?.kill()
|
||
bottomHeaderScrollTrigger?.kill()
|
||
topHeaderTween = null
|
||
bottomHeaderScrollTrigger = null
|
||
isBottomHeaderVisible = false
|
||
gsap.killTweensOf([topHeaderRef.value, bottomHeaderRef.value])
|
||
})
|
||
|
||
</script>
|
||
|
||
<template>
|
||
<header
|
||
ref="topHeaderRef"
|
||
class="site-header-top fixed left-0 right-0 top-0 z-50 mx-auto flex h-[70px] w-page-container max-w-[calc(100%-2rem)] items-center justify-between px-4 py-5"
|
||
>
|
||
<!-- 左侧:Logo 和 标题 -->
|
||
<div class="flex items-center gap-3">
|
||
<div class="logo-icon flex h-8 w-8 items-center justify-center rounded-full bg-black text-white">
|
||
<!-- 简单的极简风格 SVG Logo -->
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="h-5 w-5">
|
||
<circle cx="12" cy="12" r="10" />
|
||
<path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" />
|
||
<path d="M2 12h20" />
|
||
</svg>
|
||
</div>
|
||
<div class="flex flex-col justify-center">
|
||
<span class="text-sm font-bold leading-none tracking-wider text-black">北极新一</span>
|
||
<span class="mt-1 text-[10px] leading-none text-gray-500">ArcticNewOne</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 中间:导航链接 -->
|
||
<nav class="hidden md:flex items-center gap-8">
|
||
<a
|
||
v-for="item in navItems"
|
||
:key="item.name"
|
||
:href="item.path"
|
||
class="group relative flex items-center text-sm font-medium text-black"
|
||
>
|
||
<span class="absolute -left-3 h-1.5 w-1.5 rounded-full bg-black opacity-0 transition-all duration-300 group-hover:opacity-100"></span>
|
||
<span class="transition-transform duration-300 group-hover:translate-x-2">{{ item.name }}</span>
|
||
</a>
|
||
</nav>
|
||
|
||
<!-- 右侧:菜单图标 (使用 div 绘制) -->
|
||
<div class="menu-icon group flex h-8 w-8 cursor-pointer flex-col items-end justify-center gap-[6px]">
|
||
<div class="h-[2px] w-6 bg-black transition-all duration-300 group-hover:translate-y-[1px]"></div>
|
||
<div class="h-[2px] w-6 bg-black transition-all duration-300 group-hover:-translate-y-[1px]"></div>
|
||
</div>
|
||
</header>
|
||
|
||
<header
|
||
ref="bottomHeaderRef"
|
||
class="fixed bottom-0 left-0 right-0 z-50 mx-auto h-[70px] w-page-container max-w-[calc(100%-2rem)] bg-blue-200 px-4 py-5"
|
||
style="visibility: hidden; opacity: 0;"
|
||
>
|
||
<nav>Bottom Navigation</nav>
|
||
</header>
|
||
</template>
|