Files
arcticnewone/app/components/layouts/ArcticNewOneHeader.vue
T
virtheart c1da2963d2 style(layouts): 调整头部组件样式和尺寸
增加头部组件高度,优化logo和导航链接的尺寸及间距
改进导航链接的悬停动画效果
统一底部组件高度与头部一致
2026-04-26 22:33:14 +08:00

144 lines
4.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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-[100px] w-page-container max-w-[calc(100%-2rem)] items-center justify-between px-4 py-5"
>
<!-- 左侧Logo 标题 -->
<div class="flex items-center gap-4">
<div class="logo-icon flex h-10 w-10 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-6 w-6">
<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-base font-bold leading-none tracking-wider text-black">北极新一</span>
<span class="mt-1 text-xs leading-none text-gray-500">ArcticNewOne</span>
</div>
</div>
<!-- 中间导航链接 -->
<nav class="hidden md:flex items-center gap-20 lg:gap-28">
<a
v-for="item in navItems"
:key="item.name"
:href="item.path"
class="group flex items-center overflow-hidden font-semibold tracking-[-0.7px] text-black"
style="font-size: 1.125rem; justify-content: flex-start; position: relative;"
>
<div class="flex items-center transition-transform duration-300 group-hover:translate-x-0 -translate-x-3">
<span class="mr-1.5 h-1.5 w-1.5 rounded-full bg-black"></span>
<span>{{ item.name }}</span>
</div>
</a>
</nav>
<!-- 右侧菜单图标 (使用 div 绘制) -->
<div class="menu-icon group flex h-12 w-12 cursor-pointer flex-col items-end justify-center gap-[8px]">
<div class="h-[2px] w-10 bg-black transition-all duration-300 group-hover:translate-y-[2.5px]"></div>
<div class="h-[2px] w-10 bg-black transition-all duration-300 group-hover:-translate-y-[2.5px]"></div>
</div>
</header>
<header
ref="bottomHeaderRef"
class="fixed bottom-0 left-0 right-0 z-50 mx-auto h-[100px] 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>