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

如何在Tailwind CSS/React中点击切换Group hover及下拉菜单

问题描述

我跟着教程做了一个导航菜单,鼠标悬停时显示下拉列表,移出整个组就关闭。现在需要实现两个功能:

  1. 点击导航菜单按钮时,切换下拉菜单的显示状态
  2. 点击下拉组内任意元素时,关闭菜单

有没有Tailwind类可以直接实现点击切换hover状态?或者用React/JavaScript/CSS实现的方法?

当前代码:

<nav aria-label="primary" class="relative z-20 flex-col flex-grow hidden pb-4 md:pb-0 md:flex md:justify-end md:flex-row">
  
  <div class="relative group">
      <button class="flex flex-row items-center w-full px-4 py-4 mt-2 text-base font-bold text-left uppercase bg-transparent rounded-lg md:w-auto md:inline md:mt-0 md:ml-4 focus:outline-none font-montserrat">
          <span>First Dropdown</span>
      </button>
      <div class="absolute z-10 hidden bg-grey-200 group-hover:block">
          
          <div class="px-2 pt-2 pb-4 bg-white bg-gray-200 shadow-lg">
            <div class="grid grid-cols-1 gap-4 md:grid-cols-2">
              <p>
                dropdown content here
              </p>
            </div>
          </div>
      </div>
  </div>  
  
  <div class="relative group">
      <button class="flex flex-row items-center w-full px-4 py-4 mt-2 text-base font-bold text-left uppercase bg-transparent rounded-lg md:w-auto md:inline md:mt-0 md:ml-4 focus:outline-none font-montserrat">
          <span>Second Dropdown</span>
      </button>
      <div class="absolute z-10 hidden bg-grey-200 group-hover:block">
          
          <div class="px-2 pt-2 pb-4 bg-white bg-gray-200 shadow-lg">
            <div class="grid grid-cols-1 gap-4 md:grid-cols-2">
              <p>
                dropdown content here
              </p>
            </div>
          </div>
      </div>
  </div>   
</nav>
解决方案

Tailwind本身没有原生类可以直接通过点击切换hover状态,需要结合JavaScript或React实现交互逻辑,以下是几种可行方案:

1. React 实现方案(状态管理)

用React的useState控制下拉显示状态,同时兼容原有hover逻辑:

import { useState } from 'react';

function Navbar() {
  // 单独管理每个下拉的显示状态
  const [showFirstDropdown, setShowFirstDropdown] = useState(false);
  const [showSecondDropdown, setShowSecondDropdown] = useState(false);

  // 通用关闭下拉函数
  const closeDropdown = (setter) => setter(false);

  return (
    <nav aria-label="primary" className="relative z-20 flex-col flex-grow hidden pb-4 md:pb-0 md:flex md:justify-end md:flex-row">
      
      <div className="relative group">
          <button 
            className="flex flex-row items-center w-full px-4 py-4 mt-2 text-base font-bold text-left uppercase bg-transparent rounded-lg md:w-auto md:inline md:mt-0 md:ml-4 focus:outline-none font-montserrat"
            onClick={() => setShowFirstDropdown(!showFirstDropdown)}
            onMouseEnter={() => setShowFirstDropdown(true)}
            onMouseLeave={() => setShowFirstDropdown(false)}
          >
              <span>First Dropdown</span>
          </button>
          {/* 同时用hover状态和React状态控制显示 */}
          <div className={`absolute z-10 hidden bg-grey-200 group-hover:block ${showFirstDropdown ? 'block' : ''}`}>
              
              <div className="px-2 pt-2 pb-4 bg-white bg-gray-200 shadow-lg">
                <div className="grid grid-cols-1 gap-4 md:grid-cols-2">
                  <p onClick={() => closeDropdown(setShowFirstDropdown)}>
                    dropdown content here
                  </p>
                </div>
              </div>
          </div>
      </div>  
      
      <div className="relative group">
          <button 
            className="flex flex-row items-center w-full px-4 py-4 mt-2 text-base font-bold text-left uppercase bg-transparent rounded-lg md:w-auto md:inline md:mt-0 md:ml-4 focus:outline-none font-montserrat"
            onClick={() => setShowSecondDropdown(!showSecondDropdown)}
            onMouseEnter={() => setShowSecondDropdown(true)}
            onMouseLeave={() => setShowSecondDropdown(false)}
          >
              <span>Second Dropdown</span>
          </button>
          <div className={`absolute z-10 hidden bg-grey-200 group-hover:block ${showSecondDropdown ? 'block' : ''}`}>
              
              <div className="px-2 pt-2 pb-4 bg-white bg-gray-200 shadow-lg">
                <div className="grid grid-cols-1 gap-4 md:grid-cols-2">
                  <p onClick={() => closeDropdown(setShowSecondDropdown)}>
                    dropdown content here
                  </p>
                </div>
              </div>
          </div>
      </div>   
    </nav>
  );
}

export default Navbar;

2. 纯 JavaScript 实现方案

不用框架的话,直接通过原生JS操作DOM类名:

<nav aria-label="primary" class="relative z-20 flex-col flex-grow hidden pb-4 md:pb-0 md:flex md:justify-end md:flex-row">
  
  <div class="relative group dropdown-container">
      <button class="flex flex-row items-center w-full px-4 py-4 mt-2 text-base font-bold text-left uppercase bg-transparent rounded-lg md:w-auto md:inline md:mt-0 md:ml-4 focus:outline-none font-montserrat dropdown-trigger">
          <span>First Dropdown</span>
      </button>
      <div class="absolute z-10 hidden bg-grey-200 group-hover:block dropdown-menu">
          
          <div class="px-2 pt-2 pb-4 bg-white bg-gray-200 shadow-lg">
            <div class="grid grid-cols-1 gap-4 md:grid-cols-2">
              <p class="dropdown-item">
                dropdown content here
              </p>
            </div>
          </div>
      </div>
  </div>  
  
  <div class="relative group dropdown-container">
      <button class="flex flex-row items-center w-full px-4 py-4 mt-2 text-base font-bold text-left uppercase bg-transparent rounded-lg md:w-auto md:inline md:mt-0 md:ml-4 focus:outline-none font-montserrat dropdown-trigger">
          <span>Second Dropdown</span>
      </button>
      <div class="absolute z-10 hidden bg-grey-200 group-hover:block dropdown-menu">
          
          <div class="px-2 pt-2 pb-4 bg-white bg-gray-200 shadow-lg">
            <div class="grid grid-cols-1 gap-4 md:grid-cols-2">
              <p class="dropdown-item">
                dropdown content here
              </p>
            </div>
          </div>
      </div>
  </div>   
</nav>

<script>
// 批量处理所有下拉菜单
const dropdownContainers = document.querySelectorAll('.dropdown-container');

dropdownContainers.forEach(container => {
  const trigger = container.querySelector('.dropdown-trigger');
  const menu = container.querySelector('.dropdown-menu');
  const items = container.querySelectorAll('.dropdown-item');

  // 点击触发器切换菜单显示
  trigger.addEventListener('click', () => {
    menu.classList.toggle('block');
  });

  // 保留原有hover逻辑
  container.addEventListener('mouseenter', () => {
    menu.classList.add('block');
  });

  container.addEventListener('mouseleave', () => {
    menu.classList.remove('block');
  });

  // 点击下拉内元素关闭菜单
  items.forEach(item => {
    item.addEventListener('click', () => {
      menu.classList.remove('block');
    });
  });
});
</script>

额外优化建议

如果需要点击页面其他区域也关闭下拉,可以添加以下代码(以纯JS为例):

document.addEventListener('click', (e) => {
  dropdownContainers.forEach(container => {
    if (!container.contains(e.target)) {
      container.querySelector('.dropdown-menu').classList.remove('block');
    }
  });
});

内容的提问来源于stack exchange,提问作者BigChungus

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 04:44:58