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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 13:55:55