带有材质ui和Reactjs的嵌套侧边栏菜单
我正在尝试使用材质ui开发侧边栏菜单.我可以列出简单的清单.在我的项目中,我有一个无法实现的嵌套侧边栏菜单的要求.如果我尝试使用递归函数,则仅提供主标题菜单,而不呈现子元素.请帮助我开发它.
I am trying to develop a sidebar menu using material ui. I am able to make it for simple list. In my project I have a requirement of nested sidebar menu which I am not able to achieve. If I am trying to use recursive function it is providing only main title menu and not rendering child elements. Please help me develop it.
嵌套侧边栏菜单的代码如下,
The code for nested sidebar menu is as below,
import React, {useState} from 'react';
import { makeStyles } from '@material-ui/core/styles';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import ListItemIcon from '@material-ui/core/ListItemIcon';
import ListItemText from '@material-ui/core/ListItemText';
import Collapse from '@material-ui/core/Collapse';
import ExpandLess from '@material-ui/icons/ExpandLess';
import ExpandMore from '@material-ui/icons/ExpandMore';
const useStyles = makeStyles((theme) => ({
root: {
width: '100%',
maxWidth: 360,
backgroundColor: theme.palette.background.paper,
},
nested: {
paddingLeft: theme.spacing(4),
},
}));
export const Menu = ({items}) => {
const classes = useStyles();
const [open, setOpen] = useState(true);
const handleClick = () => {
setOpen(!open);
};
return (
items.map(item =>
!item.children ? (
<div key={item.title}>
<ListItem button>
<ListItemIcon>
{item.icon}
</ListItemIcon>
<ListItemText primary={item.title} />
</ListItem>
</div>
) : (
<div
component="nav"
key={item.title}
>
<ListItem button onClick={handleClick}>
<ListItemIcon>
{item.icon}
</ListItemIcon>
<ListItemText primary={item.title} />
{open ? <ExpandLess /> : <ExpandMore />}
</ListItem>
<Collapse in={open} timeout="auto" unmountOnExit>
<List component="div" disablePadding>
<ListItem button className={classes.nested}>
<ListItemIcon>
{item.icon}
</ListItemIcon>
<ListItemText>
<Menu items={item} />
</ListItemText>
</ListItem>
</List>
</Collapse>
</div>
)
)
);
}
菜单项代码在这里,
import HomeOutlinedIcon from "@material-ui/icons/HomeOutlined";
import LocalLibraryOutlinedIcon from "@material-ui/icons/LocalLibraryOutlined";
import TrendingUpOutlinedIcon from "@material-ui/icons/TrendingUpOutlined";
import DescriptionOutlinedIcon from "@material-ui/icons/DescriptionOutlined";
import React from "react";
export const menu = [
{
icon: <HomeOutlinedIcon/>,
title: 'Home',
items: []
},
{
icon: <LocalLibraryOutlinedIcon/>,
title: 'Education',
items: [
{
title:'Technical Analysis',
items: [
{
title: 'The Dow Theory',
to: '/thedowtheory'
},
{
title: 'Charts & Chart Patterns',
to: '/chart'
},
{
title: 'Trend & Trend Lines',
to: '/trendlines'
},
{
title: 'Support & Resistance',
to: '/sandr'
},
]
},
{
title:'Fundamental Analysis',
items: [
{
title: 'The Dow Theory',
to: '/thedowtheory'
},
{
title: 'Charts & Chart Patterns',
to: '/chart'
},
{
title: 'Trend & Trend Lines',
to: '/trendlines'
},
{
title: 'Support & Resistance',
to: '/sandr'
},
]
},
{
title:'Elliot Wave Analysis',
items: [
{
title: 'The Dow Theory',
to: '/thedowtheory'
},
{
title: 'Charts & Chart Patterns',
to: '/chart'
},
{
title: 'Trend & Trend Lines',
to: '/trendlines'
},
{
title: 'Support & Resistance',
to: '/sandr'
},
]
},
]
},
{
icon: <TrendingUpOutlinedIcon/>,
title: 'Options'
},
{
icon: <DescriptionOutlinedIcon/>,
title: 'Blog'
},
]
首先,您有一个错字.您正在循环使用 children
键而不是 items
.但是,即使您修复了该错误,您的代码仍无法按照您想要的方式工作.
First, you have a typo. You're looping on children
key instead of items
. But even though you fix that, your code won't still work the way you'll want.
我将通过创建可重复使用的 SingleLevel
和 MultiLevel
可重用组件来处理当前菜单项,从而简化方法.如果当前项目具有 children
/ items
,那么我将使用 MultiLevel
组件,否则使用 SingleLevel
.
I would simplify my approach by creating a SingleLevel
and MultiLevel
reusable components to handle the current menu item. If the current item has children
/items
then I would use the MultiLevel
component else SingleLevel
.
单级组件
const SingleLevel = ({ item }) => {
return (
<ListItem button>
<ListItemIcon>{item.icon}</ListItemIcon>
<ListItemText primary={item.title} />
</ListItem>
);
};
多层组件
const MultiLevel = ({ item }) => {
const { items: children } = item;
const [open, setOpen] = useState(false);
const handleClick = () => {
setOpen((prev) => !prev);
};
return (
<React.Fragment>
<ListItem button onClick={handleClick}>
<ListItemIcon>{item.icon}</ListItemIcon>
<ListItemText primary={item.title} />
{open ? <ExpandLessIcon /> : <ExpandMoreIcon />}
</ListItem>
<Collapse in={open} timeout="auto" unmountOnExit>
<List component="div" disablePadding>
{children.map((child, key) => (
<MenuItem key={key} item={child} />
))}
</List>
</Collapse>
</React.Fragment>
);
};
要确定要使用的组件,我将创建一个 hasChildren
帮助程序函数,如果当前项满足我所有定义的条件,则该函数将返回 true
菜单项.
To identify which component to use, I would then create a hasChildren
helper function that returns true
if the current item meets all my defined conditions to be considered as a parent menu item.
utils.js
export function hasChildren(item) {
const { items: children } = item;
if (children === undefined) {
return false;
}
if (children.constructor !== Array) {
return false;
}
if (children.length === 0) {
return false;
}
return true;
}
然后我将所有这些抽象到另一个 MenuItem
组件上.
I would then abstract all of these on a another MenuItem
component.
MenuItem组件
const MenuItem = ({ item }) => {
const Component = hasChildren(item) ? MultiLevel : SingleLevel;
return <Component item={item} />;
};
最后,这就是我如何循环 menu
项目
And lastly, this is how will I loop the menu
items
export default function App() {
return menu.map((item, key) => <MenuItem key={key} item={item} />);
}