如何修改Tailwind导航栏代码实现嵌套子菜单并解决点击嵌套项时主菜单关闭的问题
如何修改Tailwind导航栏代码实现嵌套子菜单并解决点击嵌套项时主菜单关闭的问题
我来帮你解决这个嵌套子菜单的问题~你现在遇到的核心问题是点击嵌套菜单的触发按钮时,父级菜单会被意外关闭,这是因为原代码的逻辑会一次性关闭所有下拉菜单,没考虑嵌套层级的情况。下面我一步步给你讲怎么改:
一、先优化HTML结构(确保嵌套层级正确)
原HTML已经有了嵌套的雏形,但我们可以调整样式让它更符合菜单的交互习惯,比如让嵌套的触发按钮占满宽度、箭头靠右:
<script src="https://cdn.tailwindcss.com"></script> <nav class="bg-sky-600 text-white"> <div class="container mx-auto px-4 md:flex items-center gap-6"> <!-- Logo --> <div class="flex items-center justify-between md:w-auto w-full"> <a href="#" class="py-5 px-2 text-white flex-1 font-bold">Webcrunch.com</a> <!-- 移动端菜单按钮 --> <div class="md:hidden flex items-center"> <button type="button" class="mobile-menu-button"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"> <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25H12" /> </svg> </button> </div> </div> <div class="hidden md:flex md:flex-row flex-col items-center justify-start md:space-x-1 pb-3 md:pb-0 navigation-menu"> <a href="#" class="py-2 px-3 block">Home</a> <a href="#" class="py-2 px-3 block">About</a> <!-- 主下拉菜单:Services --> <div class="relative"> <button type="button" class="dropdown-toggle py-2 px-3 hover:bg-sky-800 flex items-center gap-2 rounded"> <span class="pointer-events-none select-none">Services</span> <svg class="w-3 h-3 pointer-events-none" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" /> </svg> </button> <div class="dropdown-menu absolute hidden bg-sky-700 text-white rounded-b-lg pb-2 w-48"> <a href="#" class="block px-6 py-2 hover:bg-sky-800">Web Design</a> <a href="#" class="block px-6 py-2 hover:bg-sky-800">Web Development</a> <a href="#" class="block px-6 py-2 hover:bg-sky-800">SEO</a> <!-- 嵌套子菜单:Test --> <div class="relative"> <button type="button" class="dropdown-toggle w-full text-left py-2 px-6 hover:bg-sky-800 flex items-center gap-2 rounded"> <span class="pointer-events-none select-none">Test</span> <svg class="w-3 h-3 pointer-events-none ml-auto" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" /> </svg> </button> <div class="dropdown-menu absolute left-full top-0 hidden bg-sky-700 text-white rounded-lg pb-2 w-48"> <a href="#" class="block px-6 py-2 hover:bg-sky-800">Nested sub menu item 1</a> <a href="#" class="block px-6 py-2 hover:bg-sky-800">Nested sub menu item 2</a> </div> </div> </div> </div> <a href="#" class="py-2 px-3 block">Contact</a> </div> </div> </nav>
二、修改JavaScript逻辑(解决父菜单被误关的问题)
原JS的核心问题是:点击嵌套触发按钮时,会把所有下拉菜单都关闭,包括父级的。我们需要调整逻辑,保留父级菜单的显示状态,同时优化外部点击的判断:
document.addEventListener("DOMContentLoaded", () => { // 选择所有下拉菜单触发按钮 const dropdownToggles = document.querySelectorAll(".dropdown-toggle") dropdownToggles.forEach((toggle) => { toggle.addEventListener("click", (e) => { // 阻止事件冒泡,避免父级触发按钮的点击事件被误触发 e.stopPropagation(); // 找到当前触发按钮对应的下拉菜单 const dropdownMenu = toggle.nextElementSibling const isMenuHidden = dropdownMenu.classList.contains("hidden") if (isMenuHidden) { // 1. 找出当前触发按钮的所有祖先下拉菜单(父级、祖父级等) const ancestorMenus = []; let parent = toggle.parentElement; while (parent) { if (parent.classList.contains("dropdown-menu")) { ancestorMenus.push(parent); } parent = parent.parentElement; } // 2. 只关闭**不是当前菜单、也不是祖先菜单**的下拉菜单 document.querySelectorAll(".dropdown-menu").forEach((menu) => { if (!ancestorMenus.includes(menu) && menu !== dropdownMenu) { menu.classList.add("hidden"); } }); // 3. 打开当前菜单 dropdownMenu.classList.remove("hidden") } else { // 隐藏当前菜单 dropdownMenu.classList.add("hidden") } }) }) // 点击页面其他区域关闭所有下拉菜单 window.addEventListener("click", function (e) { // 如果点击的不是触发按钮,也不在任何下拉菜单内部,就关闭所有菜单 if (!e.target.closest(".dropdown-toggle") && !e.target.closest(".dropdown-menu")) { document.querySelectorAll(".dropdown-menu").forEach((menu) => { menu.classList.add("hidden") }) } }) // 移动端菜单切换逻辑(保留原功能) const mobileMenuButton = document.querySelector('.mobile-menu-button') const mobileMenu = document.querySelector('.navigation-menu') mobileMenuButton.addEventListener('click', () => { mobileMenu.classList.toggle('hidden') }) })
关键修改点说明
- 阻止事件冒泡:添加
e.stopPropagation(),避免点击嵌套触发按钮时,父级的触发按钮也响应点击事件。 - 保留祖先菜单:关闭菜单时,会先找出当前触发按钮的所有父级下拉菜单,关闭操作会跳过这些菜单,避免父级菜单被误关。
- 优化外部点击判断:使用
closest()方法更精准地判断点击位置,确保点击嵌套菜单内部时,不会触发全局关闭逻辑。
这样修改后,点击嵌套的"Test"按钮时,父级的"Services"菜单会保持打开,子菜单正常显示/隐藏;点击页面空白区域时,所有菜单会统一关闭,移动端的菜单功能也不受影响。
备注:内容来源于stack exchange,提问作者Max
相关产品推荐
相关产品推荐

