You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改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')
  })
})

关键修改点说明

  1. 阻止事件冒泡:添加e.stopPropagation(),避免点击嵌套触发按钮时,父级的触发按钮也响应点击事件。
  2. 保留祖先菜单:关闭菜单时,会先找出当前触发按钮的所有父级下拉菜单,关闭操作会跳过这些菜单,避免父级菜单被误关。
  3. 优化外部点击判断:使用closest()方法更精准地判断点击位置,确保点击嵌套菜单内部时,不会触发全局关闭逻辑。

这样修改后,点击嵌套的"Test"按钮时,父级的"Services"菜单会保持打开,子菜单正常显示/隐藏;点击页面空白区域时,所有菜单会统一关闭,移动端的菜单功能也不受影响。

备注:内容来源于stack exchange,提问作者Max

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.13 19:54:38