Files
youbai/src/components/layout/Header.vue
2025-06-10 12:47:00 +08:00

307 lines
10 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.
<template>
<header
class="fixed top-0 w-full z-50 transition-all duration-300"
:class="{
'bg-white/90 backdrop-blur-md shadow-sm py-3': isScrolled || isMenuOpen,
'bg-transparent py-5': !isScrolled && !isMenuOpen
}"
>
<!-- 关键修复移动端布局优化 -->
<div class="px-3 sm:px-4">
<div class="flex justify-between items-center">
<router-link to="/" class="flex items-center shrink-0">
<img src="@/assets/images/logo.png" alt="Logo" class="w-8 h-8 md:w-10 md:h-10" />
<span class="ml-2 text-base sm:text-xl md:text-2xl font-bold text-primary whitespace-nowrap">
{{ currentLang === 'zh' ? '酉佰' : 'YouBaiBai' }}
</span>
</router-link>
<nav class="hidden md:flex space-x-8">
<router-link
v-for="item in menuItems"
:key="item.path"
:to="item.path"
class="font-medium transition-colors hover:text-primary"
active-class="text-primary"
:exact="item.exact"
>
{{ item.name }}
</router-link>
</nav>
<div class="hidden md:flex items-center space-x-4">
<!-- 语言切换按钮 -->
<button
@click="toggleLanguage"
class="flex items-center justify-center w-10 h-10 rounded-full bg-gray-100 hover:bg-primary hover:text-white transition-colors"
:title="currentLang === 'zh' ? '切换为英文' : 'Switch to Chinese'"
>
{{ currentLang === 'zh' ? 'EN' : '中' }}
</button>
<button
class="bg-gradient-to-r from-blue-500 to-indigo-600 hover:from-blue-600 hover:to-indigo-700 text-white font-medium py-2 px-4 md:py-3 md:px-6 rounded-lg flex items-center justify-center transition-all duration-300 transform hover:-translate-y-1 shadow-lg hover:shadow-xl active:translate-y-0 active:shadow-md"
@click="openModal"
>
{{ currentLang === 'zh' ? '联系我们' : 'Contact' }}
</button>
</div>
<!-- 移动端菜单按钮 - 关键修复区域 -->
<div class="flex items-center space-x-2 md:hidden">
<!-- 移动端语言切换按钮 - 尺寸优化 -->
<button
@click="toggleLanguage"
class="shrink-0 flex items-center justify-center w-8 h-8 rounded-full bg-gray-100 hover:bg-primary hover:text-white transition-colors"
>
{{ currentLang === 'zh' ? 'EN' : '中' }}
</button>
<button @click="toggleMenu" class="shrink-0 text-gray-700">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M4 6h16M4 12h16m-7 6h7"
/>
</svg>
</button>
</div>
</div>
</div>
<!-- 移动端菜单 - 修复宽度问题 -->
<div
v-show="isMenuOpen"
class="w-full md:hidden fixed inset-x-0 z-50 bg-white/95 backdrop-blur-lg py-5 overflow-hidden"
:style="{ top: headerHeight + 'px', height: `calc(100vh - ${headerHeight}px)` }"
@click.self="closeMenu"
>
<div class="px-4 h-full flex flex-col">
<nav class="flex flex-col space-y-4 py-4 overflow-y-auto">
<router-link
v-for="item in menuItems"
:key="item.path"
:to="item.path"
class="font-medium text-lg py-2 transition-colors hover:text-primary"
active-class="text-primary"
@click="closeMenu"
>
{{ item.name }}
</router-link>
</nav>
<div class="pt-4 pb-8 mt-auto">
<button
class="w-full bg-primary hover:bg-blue-700 text-white font-semibold py-3 rounded-lg transition-colors"
@click="openModal(); closeMenu();"
>
{{ currentLang === 'zh' ? '联系我们' : 'Contact' }}
</button>
</div>
</div>
</div>
</header>
<!-- 模态框组件 -->
<!-- 模态框组件 - 移动端优化 -->
<transition name="modal-fade">
<div v-if="showModal" @click="closeModal" class="fixed inset-0 z-50 overflow-auto bg-black/50 flex items-start justify-center p-4 backdrop-blur-lg">
<div @click.stop class="bg-white rounded-2xl shadow-xl w-full max-w-md sm:max-w-2xl overflow-hidden transform transition-all sm:mt-20">
<!-- 模态框头部 -->
<div class="bg-gradient-to-r from-indigo-600 to-blue-700 p-4 sm:p-6 text-white">
<div class="flex justify-between items-center">
<h2 class="text-xl sm:text-2xl font-bold">{{ currentLang === 'zh' ? '留下您的联系方式' : 'Leave Your Contact' }}</h2>
<button @click="closeModal" class="text-white hover:text-gray-200">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
<!-- 模态框内容 - 移动端优化 -->
<div class="p-4 sm:p-6 max-h-[70vh] overflow-y-auto bg-gradient-to-r from-indigo-600 to-blue-700">
<ContactForm :lang="currentLang" />
</div>
<!-- 模态框底部 - 移动端优化 -->
<div class="bg-gray-50 px-4 sm:px-6 py-4 flex flex-col sm:flex-row sm:flex-wrap justify-end gap-3">
<button
@click="closeModal"
class="w-full sm:w-auto px-5 py-2 text-gray-700 rounded-lg font-medium border border-gray-300 hover:bg-gray-100"
>
{{ currentLang === 'zh' ? '关闭' : 'Close' }}
</button>
<button
class="w-full sm:w-auto px-5 py-2 bg-indigo-600 text-white rounded-lg font-medium hover:bg-indigo-700"
>
{{ currentLang === 'zh' ? '立即申请' : 'Submit' }}
</button>
</div>
</div>
</div>
</transition>
</template>
<script setup>
import { ref, computed, onMounted, onBeforeUnmount } from 'vue';
import ContactForm from "@/components/ui/ContactForm.vue";
const isScrolled = ref(false);
const isMenuOpen = ref(false);
const showModal = ref(false);
const headerHeight = ref(0);
const currentLang = ref('zh'); // 默认中文
// 新增:视口和导航宽度变量
const viewportWidth = ref(0);
const navWidth = ref(0);
// 菜单项根据语言动态变化
const menuItems = computed(() => {
return [
{ path: '/', name: currentLang.value === 'zh' ? '首页' : 'Home', exact: true },
{ path: '/about', name: currentLang.value === 'zh' ? '公司介绍' : 'About' },
{ path: '/team', name: currentLang.value === 'zh' ? '团队介绍' : 'Team' },
{ path: '/features', name: currentLang.value === 'zh' ? '服务特色' : 'Features' },
{ path: '/careers', name: currentLang.value === 'zh' ? '加入我们' : 'Careers' }
];
});
// 新增:输出视口和导航宽度
const logDimensions = () => {
// 获取视口宽度
viewportWidth.value = window.innerWidth;
// 输出到控制台
console.log('视口宽度:', `${viewportWidth.value}px`);
console.log('----------------------');
// 获取导航元素宽度
const navElement = document.querySelector('header');
if (navElement) {
navWidth.value = navElement.offsetWidth;
}
console.log('导航宽度:', `${navWidth.value}px`);
console.log('----------------------');
// 修改header标签的宽度
navElement.style.width = `${navWidth.value}px`;
// 修改body的宽度
document.body.style.width = `${viewportWidth.value}px`;
};
const toggleLanguage = () => {
currentLang.value = currentLang.value === 'zh' ? 'en' : 'zh';
};
const openModal = () => {
showModal.value = true;
};
const closeModal = () => {
showModal.value = false;
};
const toggleMenu = () => {
isMenuOpen.value = !isMenuOpen.value;
if (isMenuOpen.value) {
document.body.style.overflow = 'hidden';
} else {
document.body.style.overflow = '';
}
};
const closeMenu = () => {
isMenuOpen.value = false;
document.body.style.overflow = '';
};
const handleScroll = () => {
isScrolled.value = window.scrollY > 20;
};
// 计算头部高度用于移动菜单定位
const calculateHeaderHeight = () => {
const header = document.querySelector('header');
if (header) {
headerHeight.value = header.offsetHeight;
}
};
onMounted(() => {
window.addEventListener('scroll', handleScroll);
calculateHeaderHeight();
window.addEventListener('resize', calculateHeaderHeight);
// 新增:添加尺寸输出功能
logDimensions(); // 初始输出
window.addEventListener('resize', logDimensions); // 窗口大小变化时输出
});
onBeforeUnmount(() => {
window.removeEventListener('scroll', handleScroll);
window.removeEventListener('resize', calculateHeaderHeight);
// 新增:移除尺寸输出监听器
window.removeEventListener('resize', logDimensions);
document.body.style.overflow = ''; // 确保卸载时恢复滚动
});
</script>
<style scoped>
.router-link-exact-active {
position: relative;
}
.router-link-exact-active::after {
content: '';
position: absolute;
bottom: -3px;
left: 0;
width: 100%;
height: 2px;
background-color: #2563eb;
}
/* 模态框动画 */
.modal-fade-enter-active,
.modal-fade-leave-active {
transition: opacity 0.3s ease;
}
.modal-fade-enter-from,
.modal-fade-leave-to {
opacity: 0;
}
/* 移动端菜单宽度修复 */
@media (max-width: 767px) {
.container {
padding-left: 1rem;
padding-right: 1rem;
}
/* 确保移动菜单不会超出视口 */
.overflow-hidden {
overflow: hidden;
}
/* 防止路由链接换行 */
.router-link {
white-space: nowrap;
}
}
/* 增强模糊效果 */
.backdrop-blur-lg {
backdrop-filter: blur(12px);
}
</style>