如何在Tailwind CSS/React中点击切换Group hover及下拉菜单
问题描述
我跟着教程做了一个导航菜单,鼠标悬停时显示下拉列表,移出整个组就关闭。现在需要实现两个功能:
- 点击导航菜单按钮时,切换下拉菜单的显示状态
- 点击下拉组内任意元素时,关闭菜单
有没有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
相关产品推荐
相关产品推荐

