fiee-official-website/src/components/customHeader/size375/index.vue
2025-10-11 16:25:06 +08:00

253 lines
6.0 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>
<!-- 通用页头 -->
<NLayoutHeader
class="custom-header"
:class="{ 'header-scrolled': isScrolled }"
>
<div class="header-container">
<div class="logo" @click="handleToHome">
<NImage
style="width: 100px; max-width: 100%"
:src="FiEELogo"
preview-disabled
/>
</div>
<div
class="menu-btn"
:class="{ 'menu-open': showMenu }"
@click="toggleMenu"
>
<img
v-if="showMenu"
src="@/assets/image/375/menu-close.png"
alt="menu"
class="menu-icon"
/>
<img
v-else
src="@/assets/image/375/menu-open.png"
alt="menu"
class="menu-icon"
/>
</div>
</div>
</NLayoutHeader>
<transition name="fade-slide">
<div v-if="showMenu" class="mobile-menu-wrapper" @click.self="closeMenu">
<NConfigProvider :theme-overrides="themeOverrides">
<NMenu
mode="vertical"
:options="menuOptions"
:inverted="isScrolled"
class="mobile-menu"
accordion
v-model:value="selectedKey"
@update:value="handleMenuSelect"
/>
</NConfigProvider>
</div>
</transition>
</template>
<script setup>
import FiEELogo from "@/assets/image/header/logo.png";
import { ref, onMounted, onUnmounted } from "vue";
import { NMenu, NLayoutHeader, NImage, NIcon, NConfigProvider } from "naive-ui";
import { MenuSharp, CloseSharp } from "@vicons/ionicons5";
import { useI18n } from "vue-i18n";
import { useRouter } from "vue-router";
import { useHeaderMenuConfig } from "@/config/headerMenuConfig";
const themeOverrides = {
Menu: {
itemTextColorHover: "#000",
itemTextColorActive: "#FF7BAC",
itemTextColorActiveHover: "#fff8fb",
itemColorHover: "#FDDFE9",
itemColorActive: "#fff",
itemColorActiveHover: "#fff8fb",
},
};
const { t } = useI18n();
const router = useRouter();
const isScrolled = ref(false);
const showMenu = ref(false);
const selectedKey = ref(null);
const toggleMenu = () => {
showMenu.value = !showMenu.value;
};
const closeMenu = () => {
showMenu.value = false;
};
// 递归查找菜单项
function findMenuOptionByKey(options, key) {
for (const option of options) {
if (option.key === key) return option;
if (option.children) {
const found = findMenuOptionByKey(option.children, key);
if (found) return found;
}
}
return null;
}
// 菜单点击跳转
const handleMenuSelect = (key) => {
const option = findMenuOptionByKey(menuOptions, key);
if (option && option.href) {
router.push(option.href);
showMenu.value = false; // 跳转后收起菜单
}
};
// 使用统一的菜单配置
const menuOptions = useHeaderMenuConfig();
// 监听滚动事件
const handleScroll = () => {
//滚动距离大于100px时处理对应的header样式
isScrolled.value = window.scrollY >= 100;
};
onMounted(() => {
window.addEventListener("scroll", handleScroll);
});
onUnmounted(() => {
window.removeEventListener("scroll", handleScroll);
});
//点击回到首页
const handleToHome = () => {
router.push("/");
selectedKey.value = null; // 重置菜单选中状态
showMenu.value = false; // 在移动端同时关闭菜单
};
</script>
<style scoped lang="scss">
.custom-header {
transition: all 0.3s ease;
background: transparent;
height: 60 * 5.12px;
&.header-scrolled {
background: rgba(255, 255, 255, 0.95);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
}
.header-container {
width: 100%;
min-width: 0;
box-sizing: border-box;
padding: 0 80px;
height: 100%;
display: flex;
align-items: center;
justify-content: space-between;
}
.logo {
flex-shrink: 0;
margin-right: 12px;
display: flex;
align-items: center;
}
.logo :deep(.n-image) {
width: 94 * 5.12px;
}
.menu-btn {
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
font-size: 75px;
padding: 40px 70px;
border-radius: 30px;
background: transparent;
user-select: none;
transition: background 0.2s;
position: relative;
width: 56 * 5.12px;
.menu-icon {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%) rotate(0deg);
opacity: 1;
transition: opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1),
transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
pointer-events: none;
}
.menu-icon-close {
opacity: 0;
transform: translate(-50%, -50%) rotate(-90deg) scale(0.8);
}
&.menu-open {
.menu-icon-menu {
opacity: 0;
transform: translate(-50%, -50%) rotate(90deg) scale(0.8);
}
.menu-icon-close {
opacity: 1;
transform: translate(-50%, -50%) rotate(0deg) scale(1);
}
}
}
.mobile-menu-wrapper {
position: fixed;
top: 60 * 5.12px;
left: 0;
width: 100vw;
background: #fff;
z-index: 1100;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.08);
padding: 40px 0 80px 0;
max-height: 1500 * 5.12px;
overflow-y: auto;
// 设置CSS变量只影响当前组件的菜单
// --n-item-text-color-child-active: #ff7bac;
:deep(.n-menu-item) {
font-weight: 600;
}
// // 强制覆盖子菜单激活状态的文字颜色
// :deep(
// .n-menu
// .n-menu-item-content.n-menu-item-content--child-active
// .n-menu-item-content-header
// ) {
// color: #ff7bac !important;
// }
// // 强制覆盖所有子菜单相关的激活状态
// :deep(.n-menu-item-content--child-active) {
// color: #ff7bac !important;
// .n-menu-item-content-header {
// color: #ff7bac !important;
// }
// }
}
.fade-slide-enter-active,
.fade-slide-leave-active {
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}
.fade-slide-enter-from,
.fade-slide-leave-to {
opacity: 0;
transform: translateY(-50px);
}
</style>