242 lines
7.8 KiB
JavaScript
242 lines
7.8 KiB
JavaScript
"use client";
|
||
import Link from "next/link";
|
||
import React, { useEffect, useState } from "react";
|
||
import { usePathname } from "next/navigation";
|
||
// !text-[var(--current-color)]
|
||
export default function Nav({ color = "#fab758" }) {
|
||
const [menu, setMenu] = useState([]);
|
||
const pathname = usePathname();
|
||
|
||
useEffect(() => {
|
||
// 获取菜单数据
|
||
fetch("/api/get-menu")
|
||
.then((res) => res.json())
|
||
.then((data) => setMenu(data.menu || []));
|
||
|
||
// 点击外部区域关闭下拉菜单
|
||
const handleClickOutside = (event) => {
|
||
if (!event.target.closest('.dropdown')) {
|
||
document.querySelectorAll('.dropdown-menu').forEach(menu => {
|
||
menu.style.display = 'none';
|
||
});
|
||
}
|
||
};
|
||
|
||
// 为多级下拉菜单添加事件监听器
|
||
const handleDropdownEvents = () => {
|
||
document.querySelectorAll('.dropdown-submenu').forEach(submenu => {
|
||
submenu.addEventListener('mouseenter', function() {
|
||
const dropdownMenu = this.querySelector('.dropdown-menu');
|
||
if (dropdownMenu) {
|
||
dropdownMenu.style.display = 'block';
|
||
}
|
||
});
|
||
|
||
submenu.addEventListener('mouseleave', function() {
|
||
const dropdownMenu = this.querySelector('.dropdown-menu');
|
||
if (dropdownMenu) {
|
||
dropdownMenu.style.display = 'none';
|
||
}
|
||
});
|
||
});
|
||
};
|
||
|
||
// 等待 DOM 加载完成后初始化
|
||
if (document.readyState === 'loading') {
|
||
document.addEventListener('DOMContentLoaded', handleDropdownEvents);
|
||
} else {
|
||
// 延迟执行,确保菜单已经渲染
|
||
setTimeout(handleDropdownEvents, 100);
|
||
}
|
||
|
||
// 添加全局点击事件监听器
|
||
document.addEventListener('click', handleClickOutside);
|
||
|
||
return () => {
|
||
// 清理事件监听器
|
||
document.removeEventListener('click', handleClickOutside);
|
||
document.querySelectorAll('.dropdown-submenu').forEach(submenu => {
|
||
submenu.removeEventListener('mouseenter', handleDropdownEvents);
|
||
submenu.removeEventListener('mouseleave', handleDropdownEvents);
|
||
});
|
||
};
|
||
}, []);
|
||
|
||
// 只在顶级菜单过滤 position
|
||
const filterHeaderMenu = (items) => {
|
||
return items.filter(item => item.position === 'Header');
|
||
};
|
||
|
||
// 递归渲染菜单
|
||
const renderMenu = (items, level = 0) => {
|
||
// 顶级菜单过滤 position
|
||
if (level === 0) items = filterHeaderMenu(items);
|
||
return items.map((item) => {
|
||
const hasChildren = item.children && item.children.length > 0;
|
||
const hasHref = !!item.href && item.href !== "#";
|
||
if (hasChildren) {
|
||
return (
|
||
<li key={item.id} className={`nav-item dropdown${level > 0 ? " dropdown-submenu dropend" : ""}`}>
|
||
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||
{/* 如果有href,左侧为可点击跳转,始终用当前item的href */}
|
||
{hasHref && (
|
||
<Link
|
||
className={`${level > 0 ? "dropdown-item" : "nav-link"} !text-[.7rem] !tracking-[normal] hover:!text-[var(--current-color)] after:!text-[var(--current-color)] ${pathname === item.href ? "!text-[var(--current-color)]" : ""}`}
|
||
href={item.href}
|
||
style={{ paddingRight: 0 }}
|
||
>
|
||
{item.label}
|
||
</Link>
|
||
)}
|
||
{/* 右侧小三角,负责展开下拉 */}
|
||
<a
|
||
className={`${hasHref ? "dropdown-toggle" : (level > 0 ? "dropdown-item" : "nav-link")} !text-[.7rem] !tracking-[normal] hover:!text-[var(--current-color)] after:!text-[var(--current-color)] ${!hasHref && pathname === item.href ? "!text-[var(--current-color)]" : ""}`}
|
||
href="#"
|
||
onClick={(e) => {
|
||
e.preventDefault();
|
||
const dropdownMenu = e.target.closest('.dropdown').querySelector('.dropdown-menu');
|
||
if (dropdownMenu) {
|
||
dropdownMenu.style.display = dropdownMenu.style.display === 'block' ? 'none' : 'block';
|
||
}
|
||
}}
|
||
style={hasHref ? { paddingLeft: 8, minWidth: 24 } : {}}
|
||
>
|
||
{hasHref ? <span className="sr-only">展开</span> : item.label}
|
||
</a>
|
||
</div>
|
||
<ul className={`dropdown-menu${level > 0 ? " submenu" : ""}`}>
|
||
{renderMenu(item.children, level + 1)}
|
||
</ul>
|
||
</li>
|
||
);
|
||
} else {
|
||
return (
|
||
<li key={item.id} className="nav-item">
|
||
<Link
|
||
className={`${level > 0 ? "dropdown-item" : "nav-link"} !text-[.7rem] !tracking-[normal] hover:!text-[var(--current-color)] after:!text-[var(--current-color)] ${pathname === item.href ? "!text-[var(--current-color)]" : ""}`}
|
||
href={item.href || "#"}
|
||
>
|
||
{item.label}
|
||
</Link>
|
||
</li>
|
||
);
|
||
}
|
||
});
|
||
};
|
||
|
||
return (
|
||
<ul className="navbar-nav" style={{ "--current-color": color }}>
|
||
{renderMenu(menu)}
|
||
<style jsx>{`
|
||
.navbar-nav .dropdown-submenu {
|
||
position: relative;
|
||
}
|
||
|
||
.navbar-nav .dropdown-submenu .dropdown-menu {
|
||
top: 0;
|
||
left: 100%;
|
||
margin-top: -1px;
|
||
display: none;
|
||
position: absolute;
|
||
z-index: 1000;
|
||
}
|
||
|
||
.navbar-nav .dropdown-submenu:hover > .dropdown-menu {
|
||
display: block;
|
||
}
|
||
|
||
.dropdown-submenu.dropend .dropdown-menu {
|
||
left: 100%;
|
||
top: 0;
|
||
}
|
||
|
||
.dropdown-submenu > .dropdown-toggle::after {
|
||
display: inline-block;
|
||
margin-left: 0.255em;
|
||
vertical-align: 0.255em;
|
||
content: "";
|
||
border-top: 0.3em solid transparent;
|
||
border-right: 0;
|
||
border-bottom: 0.3em solid transparent;
|
||
border-left: 0.3em solid;
|
||
}
|
||
|
||
.dropdown-menu {
|
||
display: none;
|
||
position: absolute;
|
||
z-index: 1000;
|
||
min-width: 10rem;
|
||
padding: 0.5rem 0;
|
||
margin: 0;
|
||
font-size: 1rem;
|
||
color: #212529;
|
||
text-align: left;
|
||
list-style: none;
|
||
background-color: #fff;
|
||
background-clip: padding-box;
|
||
border: 1px solid rgba(0, 0, 0, 0.15);
|
||
border-radius: 0.375rem;
|
||
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
|
||
}
|
||
|
||
.dropdown-menu.show {
|
||
display: block;
|
||
}
|
||
|
||
.dropdown-item {
|
||
display: block;
|
||
width: 100%;
|
||
padding: 0.25rem 1rem;
|
||
clear: both;
|
||
font-weight: 400;
|
||
color: #212529;
|
||
text-align: inherit;
|
||
text-decoration: none;
|
||
white-space: nowrap;
|
||
background-color: transparent;
|
||
border: 0;
|
||
}
|
||
|
||
.dropdown-item:hover,
|
||
.dropdown-item:focus {
|
||
color: #1e2125;
|
||
background-color: #e9ecef;
|
||
}
|
||
|
||
.nav-link {
|
||
color: #6c757d;
|
||
text-decoration: none;
|
||
padding: 0.5rem 1rem;
|
||
}
|
||
|
||
.nav-link:hover {
|
||
color: var(--current-color);
|
||
}
|
||
|
||
.dropdown-submenu .dropdown-submenu .dropdown-menu {
|
||
z-index: 1001;
|
||
}
|
||
|
||
/* 确保顶级下拉菜单正确显示 */
|
||
.navbar-nav > .dropdown > .dropdown-menu {
|
||
top: 100%;
|
||
left: 0;
|
||
margin-top: 0;
|
||
}
|
||
|
||
/* 添加下拉箭头指示器 */
|
||
.dropdown-toggle::after {
|
||
display: inline-block;
|
||
margin-left: 0.255em;
|
||
vertical-align: 0.255em;
|
||
content: "";
|
||
border-top: 0.3em solid;
|
||
border-right: 0.3em solid transparent;
|
||
border-bottom: 0;
|
||
border-left: 0.3em solid transparent;
|
||
}
|
||
`}</style>
|
||
</ul>
|
||
);
|
||
}
|