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

如何在React侧边栏中实现可折叠子菜单(嵌套数组渲染)

实现可折叠侧边栏子菜单

要实现可折叠子菜单,你需要添加状态管理展开状态、处理折叠按钮的交互,并条件渲染子菜单。以下是修改后的完整代码:

import { useState } from 'react';
import { Link, useNavigate } from 'react-router-dom';
import EqualizerIcon from '@mui/icons-material/Equalizer';
import ShoppingBagIcon from '@mui/icons-material/ShoppingBag';
import InventoryIcon from '@mui/icons-material/Inventory';
import AddBoxIcon from '@mui/icons-material/AddBox';
import Avatar from '@mui/material/Avatar';
import { useDispatch, useSelector } from 'react-redux';
import './Sidebar.css';
import { useSnackbar } from 'notistack';
import { logoutUser } from '../../../actions/userAction';

import { BsChevronDown } from 'react-icons/bs';

const navMenu = [
  {
    icon: <EqualizerIcon />,
    label: "Dashboard",
    ref: "/admin/dashboard",
  },
  {
    icon: <ShoppingBagIcon />,
    label: "Orders",
    ref: "/admin/orders",
  },
  {
    icon: <InventoryIcon />,
    label: "Products",
    ref: "/admin/products",
    collapse: <BsChevronDown />,
    children: [
      {
        icon: <AddBoxIcon />,
        label: "Add Product",
        ref: "/admin/new_product",
      },
    ]
  },
];

const Sidebar = ({ activeTab, setToggleSidebar }) => {
  const dispatch = useDispatch();
  const navigate = useNavigate();
  const { enqueueSnackbar } = useSnackbar();
  const { user } = useSelector((state) => state.user);
  
  // 管理子菜单展开状态
  const [expandedMenus, setExpandedMenus] = useState({});

  // 切换子菜单展开/折叠
  const toggleSubmenu = (label) => {
    setExpandedMenus(prev => ({
      ...prev,
      [label]: !prev[label]
    }));
  };

  const handleLogout = () => {
    dispatch(logoutUser());
    enqueueSnackbar("Logout Successfully", { variant: "success" });
    navigate("/login");
  }

  return (
    <aside className="sidebar z-10 sm:z-0 block min-h-screen left-0 pb-14 max-h-screen w-3/4 sm:w-1/5 bg-gray-800 text-white overflow-x-hidden border-r">
      <div className="flex items-center gap-3 bg-gray-700 p-2 rounded-lg shadow-lg my-4 mx-3.5">
        <Avatar
          alt="Avatar"
          src={user.avatar.url}
        />
        <div className="flex flex-col gap-0">
          <span className="font-medium text-lg">{user.name}</span>
          <span className="text-gray-300 text-sm">{user.email}</span>
        </div>
      </div>

      <div className="flex flex-col w-full gap-0 my-8">
        {navMenu.map((item, index) => {
          const { icon, label, ref, children, collapse } = item;
          const isExpanded = expandedMenus[label];

          return (
            <div key={label} className="flex flex-col">
              <Link 
                to={ref} 
                className={`${activeTab === index ? "bg-gray-700" : "hover:bg-gray-700"} flex gap-3 items-center py-3 px-4 font-medium`}
              >
                <span>{icon}</span>
                <span>{label}</span>
                {collapse && (
                  <span 
                    onClick={(e) => {
                      e.preventDefault(); // 阻止导航跳转
                      toggleSubmenu(label);
                    }}
                    className={`ml-auto transition-transform ${isExpanded ? 'rotate-180' : ''}`}
                  >
                    {collapse}
                  </span>
                )}
              </Link>

              {/* 条件渲染子菜单 */}
              {isExpanded && children && (
                <div className="pl-8 bg-gray-800">
                  {children.map((child) => (
                    <Link 
                      to={child.ref} 
                      key={child.label} 
                      className={`hover:bg-gray-700 flex gap-3 items-center py-2 px-4 font-medium text-sm`}
                    >
                      <span>{child.icon}</span>
                      <span>{child.label}</span>
                    </Link>
                  ))}
                </div>
              )}
            </div>
          );
        })}
      </div>
    </aside>
  )
};

export default Sidebar;

关键修改点说明:

  • 状态管理:使用useState创建expandedMenus对象,记录每个菜单的展开状态
  • 切换函数:toggleSubmenu函数通过菜单标签切换对应项的展开状态
  • 折叠按钮交互:给折叠图标添加点击事件,阻止默认导航行为并触发状态切换,同时通过rotate-180类实现图标旋转动画
  • 子菜单渲染:根据展开状态条件渲染子菜单,使用pl-8实现缩进,text-sm区分主菜单和子菜单样式

内容的提问来源于stack exchange,提问作者Maxi Kravaykov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 09:45:29