<script> <Menu defaultSelectedKeys={[‘/home‘]} //数组类型 让那个key被选中 这个值不应该写死,应该根据路径确定 defaultOpenKeys={[‘sub1‘]} mode="inline" //菜单下拉方式 vertival theme="dark" inlineCollapsed={this.state.collapsed} >
<Menu.Item key="/home">
<Link to="/home">
<Icon type="home" />
<span>首页</span>
</Link>
</Menu.Item>
<SubMenu
key="pro"
title={
<span>
<Icon type="mail" />
<span>商品</span>
</span>
}
>
<Menu.Item key="/category">
<Link to="/category">
<Icon type="folder-open" />
<span>品类管理</span>
</Link>
</Menu.Item>
<Menu.Item key="/products">
<Link to="/products">
<Icon type="filter" />
<span>商品管理</span>
</Link>
</Menu.Item>
</SubMenu>
</Menu>
</script>
每个menu都对应一个路由,所以配对的时候用路径
Menu.Item里的key就用路径来匹配 因为是唯一的
点击menu.item里的内容应该进行路由的跳转 所以用Link包裹起来
优化:不够灵活
一个菜单主要包含图标和文字和key 导航列表应该设置成为一个配置
src/config/menuConfig.js
<script> const menuList = [ { title: ‘首页‘, // 菜单标题名称 key: ‘/home‘, // 对应的path icon: ‘home‘, // 图标名称 public: true, // 公开的 }, { title: ‘商品‘, key: ‘/products‘, icon: ‘appstore‘, children: [ // 子菜单列表 { title: ‘品类管理‘, key: ‘/category‘, icon: ‘bars‘ }, { title: ‘商品管理‘, key: ‘/product‘, icon: ‘tool‘ }, ] }, { title: ‘用户管理‘, key: ‘/user‘, icon: ‘user‘ }, { title: ‘角色管理‘, key: ‘/role‘, icon: ‘safety‘, }, { title: ‘图形图表‘, key: ‘/charts‘, icon: ‘area-chart‘, children: [ { title: ‘柱形图‘, key: ‘/charts/bar‘, icon: ‘bar-chart‘ }, { title: ‘折线图‘, key: ‘/charts/line‘, icon: ‘line-chart‘ }, { title: ‘饼图‘, key: ‘/charts/pie‘, icon: ‘pie-chart‘ }, ] }, ] export default menuList </script>
根据menuList生成标签类型,把menu里的内容显示出来
根据数组数据生成标签数组
{menuList.map(item=>(
<Menu.Item key={item.key}>
<Link to={item.key}>
<Icon type={item.icon} />
<span>{item.title}</span>
</Link>
</Menu.Item>
))}
<script> //根据指定menu数据数组生成<Menu.Item>和SubMenu的数组 //map+函数递归 renderMenu = (menuList) => { return menuList.map(item => { if (!item.children) { return (<Menu.Item key={item.key}> <Link to={item.key}> <Icon type={item.icon} /> <span>{item.title}</span> </Link> </Menu.Item> ) } return( <SubMenu key={item.key} title={ <span> <Icon type={item.icon} /> <span>{item.title}</span> </span> } > {this.renderMenu2(item.children)} </SubMenu> ) }) } render() { return ( <div className={styles.leftNav}> <header> <Link to="/" > 后台系统 </Link> </header> <Menu defaultSelectedKeys={[‘/home‘]} // defaultOpenKeys={[‘sub1‘]} mode="inline" theme="dark" inlineCollapsed={this.state.collapsed} > {this.renderMenu(menuList)} </Menu> </div> ); } } </script/>
用reduce方法实现menu
//根据指定menu数据数组生成<Menu.Item>和SubMenu的数组 // reduce+函数递归 renderMenu2=(menuList)=>{ //求奇数和 const arr1=[1,2,3,4] arr1.reduce((preTotal,item)=>{ // return preTotal + item //这样是所有元素的和 必须把当此统计的结果return 变为下次统计的初始值 return proTotal + (item%2===1?item:0) //返回奇数和 这个是便利回调函数:统计:必须返回当此统计的结果 },0) //0代表的初始总和 }
<script> renderMenu2=(menuList)=>{ // //求奇数和 // const arr1=[1,2,3,4] // arr1.reduce((preTotal,item)=>{ // // return preTotal + item //这样是所有元素的和 必须把当此统计的结果return 变为下次统计的初始值 // return proTotal + (item%2===1?item:0) //返回奇数和 这个是便利回调函数:统计:必须返回当此统计的结果 // },0) //0代表的初始总和 return menuList.reduce((pre,item)=>{ //可能向pre添加<Menu.Item></Menu.Item> if(!item.children){ pre.push(<Menu.Item key={item.key}> <Link to={item.key}> <Icon type={item.icon} /> <span>{item.title}</span> </Link> </Menu.Item>) }else{ pre.push( <SubMenu key={item.key} title={ <span> <Icon type={item.icon} /> <span>{item.title}</span> </span> } > {this.renderMenu2(item.children)} </SubMenu>) } //可能是SubMenu return pre },[]) } </script>
路由器有个模块组件叫withRouter 可以让组件获得路由方法
<script> import { Link,withRouter } from ‘react-router-dom‘ const { SubMenu } = Menu; class leftNav extends Component { state = { } //向外暴露,使用高阶组件withRouter()来包装非路由组件 //新组件向LeftNav传递3个特别属性:history/location/match //结果:leftNav可以操作路由相关语法了 export default withRouter(leftNav) </script>
<Menu defaultSelectedKeys={[‘/home‘]} //数组类型 让那个key被选中 这个值不应该写死,应该根据路径确定
//得到当前请求的路由路径:这个是路由的能力
const selectKey = this.props.location.pathname //但是this.props.location是undefied props里没有location
//这是个非路由组件,所以没有history,location 但我们需要路由里面的属性
//这时候路由组件提供了withRouter
<script> //让子菜单能自动选中 renderMenu2=(menuList)=>{ const path = this.props.location.pathname return menuList.reduce((pre,item)=>{ //可能向pre添加<Menu.Item></Menu.Item> if(!item.children){ pre.push(<Menu.Item key={item.key}> <Link to={item.key}> <Icon type={item.icon} /> <span>{item.title}</span> </Link> </Menu.Item>) }else{ /* 判断当前item的key是否是我需要的openKey 查找item的所有children中cItem的key,看是否有一个跟请求的path匹配 */ const cItem = item.children.find(cItem=>cItem.key===path) if(cItem){ this.openKey = item.key } pre.push( <SubMenu key={item.key} title={ <span> <Icon type={item.icon} /> <span>{item.title}</span> </span> } > {this.renderMenu2(item.children)} </SubMenu>) } //可能是SubMenu return pre },[]) } render() { //因为下方的this.openKey会拿不到值,因该先把子组件渲染出来拿到openKey const menuNode = this.renderMenu2(menuList) //得到当前请求的路由路径:这个是路由的能力 const selectKey = this.props.location.pathname //但是this.props.location是undefied props里没有location //这是个非路由组件,所以没有history,location 但我们需要路由里面的属性 //这时候路由组件提供了withRouter return ( <div className={styles.leftNav}> <header> <Link to="/" > 后台系统 </Link> </header> <Menu defaultSelectedKeys={[selectKey]} //这个值应该根据路径进行变化,而不是固定的 defaultOpenKeys={[this.openKey]} //没有这个的时候,路径为子菜单的时候,不会展开,看不到,需要请求到子路由的时候让他自动展开 mode="inline" theme="dark" inlineCollapsed={this.state.collapsed} > {menuNode} </Menu> </div> </script>
优化:从login进入admin会进行两次render
理由是:login页面点击登陆后使用了this.props.history.replace进行跳转进入‘/ ’,这时候LeftNav组件进行第一次渲染,然后进入Content组件,遇到<Redirect to="/home" />又进行匹配 进行跳转
这个时候其实要进入App.js里进行匹配,App.js只有‘/login‘ 和 ’/ ‘ ,其实进行的是模糊匹配 ’/home‘匹配不到login就会去匹配 ‘/ ‘
要设置成精确匹配 使用exact={true} 但是不能使用这个 只用这个 ‘/home‘就匹配不到
{/**/}
defaultSelectKeys:总是根据据第一次指定的key进行显示
selectedKeys:总是根据最新指定的key进行显示 ;所以用这个
原文地址:https://www.cnblogs.com/lucy-xyy/p/11831107.html