React项目中如何实现点击显示、移开隐藏的下拉菜单?
解决React下拉菜单显示/隐藏问题
核心问题分析
你的代码缺少状态管理来控制下拉菜单的显示与隐藏,且直接操作DOM的方式不符合React组件化思维。我们需要通过React的useState钩子管理菜单状态,并通过事件处理器实现交互逻辑。
修复步骤
1. 更新Navigation.jsx,添加状态管理与交互逻辑
- 引入
useState钩子 - 添加控制下拉菜单可见性的状态
- 为Services选项添加点击事件切换菜单状态
- 传递状态和隐藏回调给
MenuDropdown组件 - 为其他导航项添加点击隐藏菜单的逻辑
修改后的Navigation.jsx代码:
import logo from './favicon.png' import { motion } from "framer-motion" import { useInView } from "react-intersection-observer" import MenuDropdown from "./MenuDropdown" import { Link } from 'react-router-dom' import { useState } from 'react' export default function Navigation() { const [ref, inView] = useInView({ triggerOnce: false }) const [isDropdownVisible, setIsDropdownVisible] = useState(false) const hideDropdown = () => setIsDropdownVisible(false) return ( <motion.nav className="flex items-center justify-between flex-wrap px-6 lg:px-12 py-8 max-w-full mx-auto" ref={ref} initial={{ y: -10, opacity: 0 }} animate={inView? { y: 0, opacity: 1 }: {}} exit={{ y: -10, opacity: 0 }} transition={{ duration: 0.5 }}> <a href="/" className="flex flex-row items-center flex-shrink-0 text-white mr-6 lg:pr-16 space-x-2"> <img src={logo} className='w-8 h-8' alt='Logo'></img> <h2 className="font-bold text-2xl tracking-tight">Sample </h2> </a> <div id='menu' className="block lg:hidden"> <button className="flex items-center px-3 py-2 border rounded text-slate-200 border-slate-400 duration-100 hover:text-white hover:border-white"> <svg className="fill-current h-3 w-3" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><title>Menu</title><path d="M0 3h20v2H0V3zm0 6h20v2H0V9zm0 6h20v2H0v-2z"/></svg> </button> </div> <div className="lg:flex flex-none w-6/12 hidden"> <div className="lg:flex-grow flex flex-rows space-x-12 text-sm"> <div className="flex flex-rows items-center space-x-2 text-white" onClick={hideDropdown}> <span className="ring-1 p-0.5 ring-white rounded-full"></span> <Link to="projects" className="block mt-4 lg:inline-block lg:mt-0 text-white mr-4"> Home </Link> </div> <div id="mega-menu" className="flex flex-rows items-center space-x-2 text-white"> <span className="ring-1 p-0.5 ring-white rounded-full"></span> <div className="block mt-4 lg:inline-block lg:mt-0 mr-4 cursor-pointer" onClick={() => setIsDropdownVisible(!isDropdownVisible)}> Services </div> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1} stroke="currentColor" className="w-4 h-4"> <path strokeLinecap="round" strokeLinejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" /> </svg> </div> <div className="flex flex-rows items-center space-x-2 text-white" onClick={hideDropdown}> <span className="ring-1 p-0.5 ring-white rounded-full"></span> <a href="about" className="block mt-4 lg:inline-block lg:mt-0 text-white mr-4"> About </a> </div> <div className="flex flex-rows items-center space-x-2 text-white" onClick={hideDropdown}> <span className="ring-1 p-0.5 ring-white rounded-full"></span> <a href="careers" className="block mt-4 lg:inline-block lg:mt-0 text-white mr-4"> Careers </a> </div> <div className="flex flex-rows items-center space-x-2 text-white" onClick={hideDropdown}> <span className="ring-1 p-0.5 ring-white rounded-full"></span> <a href="contact" className="block mt-4 lg:inline-block lg:mt-0 text-white mr-4"> Contact </a> </div> </div> </div> <MenuDropdown isVisible={isDropdownVisible} onHide={hideDropdown}></MenuDropdown> </motion.nav> ) }
2. 更新MenuDropdown.jsx,接收状态并添加鼠标离开事件
- 添加props参数接收
isVisible和onHide - 动态控制
hidden类的显示 - 为菜单容器添加鼠标离开事件触发隐藏
修改后的MenuDropdown.jsx代码:
import { Link } from "react-router-dom" const MenuDropdown = ({ isVisible, onHide }) => { return ( <div className={`absolute top-20 right-0 bg-white shadow-lg text-gray-500 w-full mx-auto p-12 ${isVisible ? '' : 'hidden'}`} onMouseLeave={onHide}> <div className="flex flex-row flex-nowrap space-x-6 justify-between"> <div className="space-y-2 flex-none w-3/12 border-r"> <h2 className="text-2xl font-semibold text-slate-900">Services</h2> <p className="text-base">Lorem Ipsum es simplemente el texto de relleno de las imprentas y archivos de texto..</p> </div> <div className="flex flex-col space-y-4"> <h2 className="text-base text-slate-900 font-bold">Option 1</h2> <p className="text-sm">Lorem Ipsum es simplemente el texto de relleno de las imprentas y archivos de texto..</p> <Link to="strategy"> <button className="border border-slate-900 flex-none w-6/12 text-black py-2 px-4 rounded-full capitalize text-center hover:bg-slate-900 hover:text-white"> <span className="text-xs">Learn More</span> </button> </Link> </div> <div className="flex flex-col space-y-4"> <h2 className="text-base text-slate-900 font-bold">Option 2</h2> <p className="text-sm">Lorem Ipsum es simplemente el texto de relleno de las imprentas y archivos de texto..</p> <Link to="design"> <button className="border border-slate-900 flex-none w-6/12 text-black py-2 px-4 rounded-full capitalize text-center hover:bg-slate-900 hover:text-white"> <span className="text-xs">Learn More</span> </button> </Link> </div> <div className="flex flex-col space-y-4"> <h2 className="text-base text-slate-900 font-bold">Option 3</h2> <p className="text-sm">Lorem Ipsum es simplemente el texto de relleno de las imprentas y archivos de texto.</p> <Link to="technology"> <button className="border border-slate-900 flex-none w-6/12 text-black py-2 px-4 rounded-full capitalize text-center hover:bg-slate-900 hover:text-white"> <span className="text-xs">Learn More</span> </button> </Link> </div> </div> </div> ) } export default MenuDropdown
额外优化建议
- 可添加点击页面其他区域隐藏菜单的逻辑(需监听document的click事件)
- 为菜单显示/隐藏添加过渡动画(可使用framer-motion或Tailwind的transition类)
- 避免直接使用
document.getElementById,React中优先通过状态和props管理组件交互
内容的提问来源于stack exchange,提问作者Maria
相关产品推荐
相关产品推荐

