React菜单问题:点击父菜单时所有子菜单展开,如何仅展开对应子菜单?
问题:点击父菜单时所有子菜单同时展开,需实现仅展开对应子菜单
我开发了带多级子菜单的导航,但现在点击任意父菜单时,所有子菜单都会展开。希望实现点击某个父菜单时,只展开它对应的子菜单。
原代码如下:
const [subMenu, setSubMenu] = useState(false) const routes = [ { name: 'Welcome', path: '/intro', logo: <ArrowRight />, items: [ { item: 'About the course' }, { item: 'How to use platform' }, { item: 'Diagnostic test' }, ], }, { name: 'Lesson 1', path: '/lesson_1', logo: <ArrowRight />, items: [ { item: 'About the course' }, { item: 'How to use platform' }, { item: 'Diagnostic test' }, ], }, ] return ( <nav className="flex flex-col border-b pb-7"> {routes.map((i, index) => { return ( <div> <div onClick={() => setSubMenu(!subMenu)} className="flex flex-row items-center justify-between mx-2 my-1 transform pl-6 transition-transform ease-in duration-200 text-gray-500 hover:bg-slate-100 rounded-lg " > <p className="text-lg">{i.name}</p> <span className="inline-flex items-center h-12 w-8 text-lg"> {i.logo} </span> </div> <div> {subMenu && ( <div> {i.items.map((i, ind) => { return ( <div key={ind} className="flex flex-col mx-5 my-1 transform pl-3 py-2 transition-transform ease-in duration-200 text-gray-500 hover:bg-slate-100 rounded-lg " > {i.item} </div> ) })} </div> )} </div> </div> ) })} </nav> )
问题原因
你用了一个全局布尔状态subMenu控制所有子菜单的显示/隐藏,点击任何父菜单都会切换这个状态,导致所有子菜单同步展开或收起。
解决方案
把状态改成记录当前展开的菜单索引(或唯一标识),精准控制单个菜单的展开状态:
修改后的代码
// 初始状态设为null,表示无菜单展开 const [expandedMenuIndex, setExpandedMenuIndex] = useState(null) const routes = [ { name: 'Welcome', path: '/intro', logo: <ArrowRight />, items: [ { item: 'About the course' }, { item: 'How to use platform' }, { item: 'Diagnostic test' }, ], }, { name: 'Lesson 1', path: '/lesson_1', logo: <ArrowRight />, items: [ { item: 'About the course' }, { item: 'How to use platform' }, { item: 'Diagnostic test' }, ], }, ] return ( <nav className="flex flex-col border-b pb-7"> {routes.map((route, index) => { // 判断当前菜单是否处于展开状态 const isExpanded = expandedMenuIndex === index return ( <div key={index}> <div onClick={() => { // 点击切换:当前展开则收起,否则展开当前菜单 setExpandedMenuIndex(isExpanded ? null : index) }} className="flex flex-row items-center justify-between mx-2 my-1 transform pl-6 transition-transform ease-in duration-200 text-gray-500 hover:bg-slate-100 rounded-lg " > <p className="text-lg">{route.name}</p> <span className="inline-flex items-center h-12 w-8 text-lg"> {route.logo} </span> </div> <div> {/* 仅当前菜单展开时显示子菜单 */} {isExpanded && ( <div> {route.items.map((item, ind) => { return ( <div key={ind} className="flex flex-col mx-5 my-1 transform pl-3 py-2 transition-transform ease-in duration-200 text-gray-500 hover:bg-slate-100 rounded-lg " > {item.item} </div> ) })} </div> )} </div> </div> ) })} </nav> )
可选优化:支持同时展开多个菜单
如果需要允许多个父菜单同时展开,可将状态改为数组记录所有展开的索引:
const [expandedMenuIndexes, setExpandedMenuIndexes] = useState([]) // 点击逻辑修改为: onClick={() => { if (expandedMenuIndexes.includes(index)) { // 已展开,移除当前索引 setExpandedMenuIndexes(expandedMenuIndexes.filter(i => i !== index)) } else { // 未展开,添加当前索引 setExpandedMenuIndexes([...expandedMenuIndexes, index]) } }} // 判断展开状态修改为: const isExpanded = expandedMenuIndexes.includes(index)
内容的提问来源于stack exchange,提问作者JohnPix
相关产品推荐
相关产品推荐

