React+Tailwind移动端菜单切换咨询:类名状态控制方案
解决方案:通过React状态动态切换类名实现移动端菜单
你只需要修改组件文件就能实现需求,样式文件的现有代码完全够用。核心思路是利用React的布尔状态,动态给目标元素添加/移除类名,同时处理屏幕尺寸变化和菜单项点击关闭的逻辑。
具体修改步骤:
修复状态初始化错误
你当前把menuIsOpen初始值设成了字符串"false",这会导致后续取反操作类型混乱。改成布尔值false:const [menuIsOpen, setMenuIsOpen] = useState(false);动态切换汉堡按钮的
open类
给汉堡按钮的className添加条件判断,当菜单打开时加上open类,触发样式里的汉堡动画:<button onClick={navToggle} name="menu-btn" id="menu-btn" className={`block hamburger lg:hidden focus:outline-none ${menuIsOpen ? 'open' : ''}`} type="button" > <span className="hamburger-top"></span> <span className="hamburger-middle"></span> <span className="hamburger-bottom"></span> </button>动态控制移动端菜单的显示/隐藏
移动端菜单的className里,把固定的hidden改成条件判断:当菜单打开时显示(用block),否则隐藏(hidden):<div id="menu" className={`absolute p-6 rounded-lg bg-darkViolet left-6 right-6 top-20 z-100 ${menuIsOpen ? 'block' : 'hidden'}`} > {/* 菜单内容 */} </div>适配屏幕尺寸变化
监听窗口resize事件,当屏幕宽度达到Tailwind的lg断点(默认1024px)时,自动关闭移动端菜单。需要在组件里添加useEffect:useEffect(() => { const handleResize = () => { if (window.innerWidth >= 1024) { setMenuIsOpen(false); } }; window.addEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize); }, []);别忘了导入
useEffect:import React, {useState, useEffect} from 'react';点击移动端菜单项关闭菜单
给每个移动端的NavLink添加onClick事件,点击后关闭菜单:<NavLink to='/' onClick={() => setMenuIsOpen(false)} className="w-full text-center">Home</NavLink> <NavLink to='/about' onClick={() => setMenuIsOpen(false)} className="w-full text-center">About</NavLink> <NavLink to='/services' onClick={() => setMenuIsOpen(false)} className="w-full text-center">Services</NavLink> <NavLink to='/contacts' onClick={() => setMenuIsOpen(false)} className="w-full text-center">Contact us</NavLink>
修改后的完整组件代码:
import React, {useState, useEffect} from 'react'; import mainLogo from '../../../public/assets/images/logo.png'; import {NavLink} from "@remix-run/react"; const Header = () => { const [menuIsOpen, setMenuIsOpen] = useState(false); // Toggle Mobile Menu const navToggle= () => { setMenuIsOpen(!menuIsOpen); }; // 监听屏幕尺寸变化,适配lg断点 useEffect(() => { const handleResize = () => { if (window.innerWidth >= 1024) { setMenuIsOpen(false); } }; window.addEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize); }, []); return ( <> {/*Nav Container*/} <nav className="relative container mx-auto p-6"> {/*Flex Container For All Items*/} <div className="flex items-center justify-between"> {/*Flex Container For Logo/Menu*/} <div className="flex items-center space-x-20"> {/*Logo*/} <NavLink className='d-lg-none' to='/'> <img src={mainLogo} alt='Logo' /> </NavLink> {/*Left Menu*/} <div className="hidden space-x-8 font-bold lg:flex"> <NavLink to='/' className="text-grayishViolet hover:text-veryDarkViolet"> Home </NavLink> <NavLink to='/about' className="text-grayishViolet hover:text-veryDarkViolet"> About </NavLink> <NavLink to='/services' className="text-grayishViolet hover:text-veryDarkViolet"> Products & Businesses </NavLink> <NavLink to='/contacts' className="text-grayishViolet hover:text-veryDarkViolet"> Contact us </NavLink> </div> </div> {/*Right Buttons Menu*/} <div className="hidden items-center space-x-6 font-bold text-grayishViolet lg:flex" > <div className='header-mail d-xl-block d-none'> Email: xxx@xxxxxxxxxxxxx.xxx </div> </div> {/*Hamburger Button*/} <button onClick={navToggle} name="menu-btn" id="menu-btn" className={`block hamburger lg:hidden focus:outline-none ${menuIsOpen ? 'open' : ''}`} type="button" > <span className="hamburger-top"></span> <span className="hamburger-middle"></span> <span className="hamburger-bottom"></span> </button> </div> {/*Mobile Menu*/} <div id="menu" className={`absolute p-6 rounded-lg bg-darkViolet left-6 right-6 top-20 z-100 ${menuIsOpen ? 'block' : 'hidden'}`} > <div className="flex flex-col items-center justify-center w-full space-y-6 font-bold text-white rounded-sm" > <NavLink to='/' onClick={() => setMenuIsOpen(false)} className="w-full text-center">Home</NavLink> <NavLink to='/about' onClick={() => setMenuIsOpen(false)} className="w-full text-center">About</NavLink> <NavLink to='/services' onClick={() => setMenuIsOpen(false)} className="w-full text-center">Services</NavLink> <NavLink to='/contacts' onClick={() => setMenuIsOpen(false)} className="w-full text-center">Contact us</NavLink> </div> </div> </nav> </> ); }; export default Header;
为什么不需要修改样式文件?
你现有的样式文件已经定义了.open类对应的汉堡动画效果,只需要在组件里根据状态动态给按钮添加这个类就行,不需要改动CSS代码。
内容的提问来源于stack exchange,提问作者MIike Eps
相关产品推荐
相关产品推荐

