如何在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
相关产品推荐
相关产品推荐

