From dcb8161f8e56646176507a90d8ef0c4ffe55b41f Mon Sep 17 00:00:00 2001 From: jingrow Date: Mon, 25 Aug 2025 01:04:28 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=89=8B=E6=9C=BA=E7=AB=AF?= =?UTF-8?q?=E5=AD=90=E8=8F=9C=E5=8D=95=E6=97=A0=E6=B3=95=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/headers/Nav.jsx | 205 ++++++++++++++++++++++++++++--------- 1 file changed, 154 insertions(+), 51 deletions(-) diff --git a/components/headers/Nav.jsx b/components/headers/Nav.jsx index 62f747d..7f696ac 100644 --- a/components/headers/Nav.jsx +++ b/components/headers/Nav.jsx @@ -2,69 +2,65 @@ 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(() => { - // Dynamically import Bootstrap - import("bootstrap").then((Bootstrap) => { - const CLASS_NAME = "has-child-dropdown-show"; - - // Save the original toggle function - const originalToggle = Bootstrap.Dropdown.prototype.toggle; - - // Override the toggle function - Bootstrap.Dropdown.prototype.toggle = function () { - // Remove the CLASS_NAME from all dropdowns - document.querySelectorAll("." + CLASS_NAME).forEach(function (e) { - e.classList.remove(CLASS_NAME); - }); - - // Traverse up through the closest dropdown parents - let dd = this._element - .closest(".dropdown") - .parentNode.closest(".dropdown"); - for (; dd && dd !== document; dd = dd.parentNode.closest(".dropdown")) { - dd.classList.add(CLASS_NAME); - } - - // Call the original toggle function - return originalToggle.call(this); - }; - - // Add event listeners for hide.bs.dropdown to remove the CLASS_NAME - document.querySelectorAll(".dropdown").forEach(function (dd) { - dd.addEventListener("hide.bs.dropdown", function (e) { - if (this.classList.contains(CLASS_NAME)) { - this.classList.remove(CLASS_NAME); - e.preventDefault(); - } - e.stopPropagation(); - }); - }); - }); - - // 获取菜单数据 fetch("/api/get-menu") .then((res) => res.json()) .then((data) => setMenu(data.menu || [])); - // Optional cleanup function for any potential side effects + const handleClickOutside = (event) => { + if (window.innerWidth <= 768) { + if (!event.target.closest('.navbar-nav .offcanvas-body .dropdown')) { + document.querySelectorAll('.navbar-nav .offcanvas-body .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'; + } + }); + }); + }; + + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', handleDropdownEvents); + } else { + setTimeout(handleDropdownEvents, 100); + } + + document.addEventListener('click', handleClickOutside); + return () => { - // Cleanup code here (if needed) + 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; @@ -73,7 +69,6 @@ export default function Nav({ color = "#fab758" }) { return (
  • 0 ? " dropdown-submenu dropend" : ""}`}>
    - {/* 如果有href,左侧为可点击跳转,始终用当前item的href */} {hasHref && ( 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)]" : ""}`} @@ -83,15 +78,21 @@ export default function Nav({ color = "#fab758" }) { {item.label} )} - {/* 右侧小三角,负责展开下拉 */} 0 ? "dropdown-item" : "nav-link") + " dropdown-toggle"} !text-[.7rem] !tracking-[normal] hover:!text-[var(--current-color)] after:!text-[var(--current-color)] ${!hasHref && pathname === item.href ? "!text-[var(--current-color)]" : ""}`} + 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="#" - data-bs-toggle="dropdown" - aria-expanded="false" + onClick={(e) => { + if (window.innerWidth <= 768) { + 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 ? 展开 : item.label} + {hasHref ? Open : item.label}