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

React中如何获取点击项的相邻兄弟元素并切换子菜单?

实现点击导航项切换子菜单的动态方案

你需要通过点击导航标题切换对应子菜单的显示/隐藏,下面提供两种实现方案,其中更符合React开发理念的是状态管理方案:

方案一:React状态管理(推荐)

这种方式完全基于数据驱动视图,不需要直接操作DOM,能避免DOM操作带来的潜在状态不一致问题。

代码实现

import { useState } from 'react';
import { Link } from 'react-router-dom'; // 假设使用react-router的Link组件

const NavMenu = () => {
  // 用对象存储每个导航项的展开状态
  const [expandedMenus, setExpandedMenus] = useState({
    'nav-a': false,
    'nav-b': false
  });

  // 切换指定导航项的展开状态
  const toggleSubMenu = (menuKey) => {
    setExpandedMenus(prevState => ({
      ...prevState,
      [menuKey]: !prevState[menuKey]
    }));
  };

  return (
    <ul>
      <li>
        <Link onClick={() => toggleSubMenu('nav-a')}>Nav Item A</Link>
        {/* 根据状态动态添加show类 */}
        <ul className={`submenu ${expandedMenus['nav-a'] ? 'show' : ''}`}>
          <li><Link to="#0">Submenu Item 1</Link></li>
          <li><Link to="#0">Submenu Item 2</Link></li>
        </ul>
      </li>

      <li>
        <Link onClick={() => toggleSubMenu('nav-b')}>Nav Item B</Link>
        <ul className={`submenu ${expandedMenus['nav-b'] ? 'show' : ''}`}>
          <li><Link to="#0">Submenu Item 1</Link></li>
          <li><Link to="#0">Submenu Item 2</Link></li>
        </ul>
      </li>
    </ul>
  );
};

export default NavMenu;

配套CSS

.submenu {
  display: none;
}
.submenu.show {
  display: block;
}

方案二:直接操作DOM(不推荐)

如果一定要通过操作Link的下一个兄弟元素来添加类,可以利用事件对象获取DOM元素并切换类名,但这种方式不符合React的设计理念,可能导致组件重新渲染后状态失效。

代码实现

修改你的toggleSubMenu函数:

const toggleSubMenu = (e) => {
  // 阻止Link默认跳转(如果不需要跳转的话)
  e.preventDefault();
  // 获取当前点击的Link元素
  const linkElement = e.currentTarget;
  // 获取下一个兄弟元素(子菜单ul)
  const subMenuElement = linkElement.nextElementSibling;
  // 切换show类
  subMenuElement.classList.toggle('show');
};

同样需要配套上面的CSS样式来控制子菜单的显示隐藏。

内容的提问来源于stack exchange,提问作者Anthon Santhez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 23:31:00