最近在学习react时,用到了很流行的UI框架Ant Design,也了解了一下Ant Design Pro,发现它们都有导航组件,Ant Design框架的导航菜单在这里,Ant Design Pro是权限菜单,权限菜单简单来说就是根据登录的权限来展示不同的菜单给用户,比如管理员有给用户分配不同角色的权限,那管理员就可以看到系统管理等导航菜单,而用户A只有发布某些业务的权限,那用户A就不能看到系统管理的导航菜单等等。不过这不在我们本文的考虑范围内,有兴趣的同学可以自行去看它的API:Authorized权限。
本次分享的是与用户权限无关的“React+Ant Design设置左侧菜单导航路由的显示与隐藏”。这个具体的功能如下:
1、如果当前路由没有子路由且该路由的hidden为false或不设置该路由的hidden时则直接显示该路由,若该路由的hidden为true则不显示该路由;
2、当子路由只有一个且该子路由的hidden为false或不设置该子路由的hidden时则显示其父路由和下拉的子路由;
3、当子路由只有一个且该子路由的hidden为true同时其父路由的hidden为false或不设置其父路由的hidden时则显示其父路由;
4、当当前路由有两个及两个以上子路由时,若两个子路由的hidden都为true时则该路由和其子路由全部隐藏,若但凡有一个子路由的hidden为false或不设置该路由的hidden时,则显示其父路由和该下拉的子路由。
看起来有点晕是吧,嗯,那就举一个简单的例子吧:
1、比如当前有一个列表页,用户可以查看每一条item的详情,但详情这个路由我们不希望出现在左侧菜单吧,因为详情页面我们是要靠传一些参数然后去请求接口才能显示出来的,不能让用户直接点击详情菜单就进页面去了,否则用户看到的就只能是一个空白的详情页,因此详情菜单导航是必须要隐藏起来的,用户只有点击了列表页每一条item的详情链接才能进入到详情页。
如图:
这种情况肯定是不对的,不能让用户直接看到详情的导航菜单。
这种把详情菜单给隐藏起来的,才是正确的做法。
2、再比如,既然一个导航菜单有下拉子菜单了,那么该导航菜单必定是只能点击展开或收起它的子菜单,如果它的子菜单都隐藏了,那它也就没有展示出来的必要了(注意,这里有一个特殊的情况就是如果所有的子路由都隐藏了,如果你还想显示其父路由,就如同例子1,列表页只有一个详情子路由,但是该子路由是隐藏的,那么就要展示父路由列表页了,此时可以设置为父路由的hidden为false或不设置hidden;另外一种情况就是所有子路由都隐藏了,而其父路由只是承担着展开收起的功能,此时父路由也是要隐藏掉的,那么就必须要设置父路由的hidden为true了。)。
那么接下来就说说实现吧。
首先,我用的是Ant Design的Layout的侧边布局以及自定义触发器。
其次,我是把左侧菜单的配置给单独拎了出来,便于实现面包屑导航和左侧菜单的默认展开及选中。
代码如下:
左侧菜单导航配置slideBarConfig.jsx:
const slideBarConfig = [
{name: "列表", icon: "ordered-list", url: "/list", children: [
{name: "详情", url: "/list/detail", hidden: true},
]},
{name: "系统管理", icon: "appstore", url: "/system", children: [
{name: "账号管理", url: "/system/accountManage"},
{name: "角色管理", url: "/system/roleManage"}
]},
{name: "兄弟组件传值", icon: "hdd", url: "/childToChild", hidden: true,},
{name: "父组件向子组件传值", icon: "snippets", url: "/parentToChild"},
{name: "子组件向父组件传值", icon: "copy", url: "/childToParent"},
{name: "状态管理Redux", icon: "inbox", url: "/redux"}
];
export default slideBarConfig;
处理左侧菜单导航路由的显示与隐藏的关键代码:
getSubmenu = () => {
return slideBarConfig.map(item => {
if(!item.children || item.children.length === 0){ //如果当前路由没有子路由且该路由的hidden为false或不设置该路由的hidden时则直接显示该路由,若该路由的hidden为true则不显示该路由
if(item.hidden) return false
return (
<MenuItem key={item.url}>
<Link to={item.url} replace> {/*加一个replace是因为当前路由下的 history 不能 push 相同的路径到 stack 里。只有开发环境存在,生产环境不存在,目前还没看到官方有去掉的意思*/}
<Icon type={item.icon} />
<span>{item.name}</span>
</Link>
</MenuItem>
)
}else if(item.children && item.children.length === 1){
if(item.hidden) return false
let noHiddenRouter = [];
let hiddenRouter = [];
item.children.map(v => {
if(v.hidden){
hiddenRouter.push(v)
}else{
noHiddenRouter.push(v)
}
return true
})
if(hiddenRouter.length > 0){ //当子路由只有一个且该子路由的hidden为true同时其父路由的hidden为false或不设置其父路由的hidden时则显示其父路由
return <MenuItem key={item.url}><Link to={item.url} replace><Icon type={item.icon} /><span>{item.name}</span></Link></MenuItem>
}
if(noHiddenRouter.length > 0){ //当子路由只有一个且该子路由的hidden为false或不设置该子路由的hidden时则显示其父路由和下拉的子路由
return (
<SubMenu key={item.url} title={<span><Icon type={item.icon} /><span>{item.name}</span></span>}>
{
noHiddenRouter.map(v => {
return <MenuItem key={v.url}><Link to={v.url} replace>{v.name}</Link></MenuItem>
})
}
</SubMenu>
)
}
}else if(item.children && item.children.length > 1){ //当当前路由有两个及两个以上子路由时,若两个子路由的hidden都为true时则该路由和其子路由全部隐藏
if(item.hidden) return false
let noHiddenRouter = [];
item.children.map(v => {
if(v.hidden){
return <MenuItem key={item.url}><Link to={item.url} replace><Icon type={item.icon} /><span>{item.name}</span></Link></MenuItem>
}else{
noHiddenRouter.push(v)
return true
}
})
if(noHiddenRouter.length > 0){
return (
<SubMenu key={item.url} title={<span><Icon type={item.icon} /><span>{item.name}</span></span>}>
{
noHiddenRouter.map(v => {
return <MenuItem key={v.url}><Link to={v.url} replace>{v.name}</Link></MenuItem>
})
}
</SubMenu>
)
}
}
return true
});
}
具体引入到layout.jsx中如下:
import React, { Component } from "react";
import {Layout, Menu, Icon } from 'antd'
import { Link } from 'react-router-dom'
import slideBarConfig from "@/layout/slideBarConfig"
import Top from '@/components/header'
import Contents from "@/layout/content"
import Http from '@/api/sendRequestApi'
import './index.css';
const { Sider, Footer } = Layout
const { SubMenu } = Menu;
const MenuItem = Menu.Item;
class Container extends Component {
constructor(props){
super(props)
this.state = {
collapsed: false,
left: 200,
}
}
toggleCollapsed = () => {
let { collapsed, left } = this.state;
this.setState({
collapsed: !collapsed,
});
if(left === 200){
this.setState({
left: 80,
});
}else{
this.setState({
left: 200,
});
}
}
logout = () => {
Http.logout().then(() => {
sessionStorage.clear();
this.props.history.push("/login");
});
}
//处理左侧菜单
getSubmenu = () => {
return slideBarConfig.map(item => {
if(!item.children || item.children.length === 0){ //如果当前路由没有子路由且该路由的hidden为false或不设置该路由的hidden时则直接显示该路由,若该路由的hidden为true则不显示该路由
if(item.hidden) return false
return (
<MenuItem key={item.url}>
<Link to={item.url} replace> {/*加一个replace是因为当前路由下的 history 不能 push 相同的路径到 stack 里。只有开发环境存在,生产环境不存在,目前还没看到官方有去掉的意思*/}
<Icon type={item.icon} />
<span>{item.name}</span>
</Link>
</MenuItem>
)
}else if(item.children && item.children.length === 1){
if(item.hidden) return false
let noHiddenRouter = [];
let hiddenRouter = [];
item.children.map(v => {
if(v.hidden){
hiddenRouter.push(v)
}else{
noHiddenRouter.push(v)
}
return true
})
if(hiddenRouter.length > 0){ //当子路由只有一个且该子路由的hidden为true同时其父路由的hidden为false或不设置其父路由的hidden时则显示其父路由
return <MenuItem key={item.url}><Link to={item.url} replace><Icon type={item.icon} /><span>{item.name}</span></Link></MenuItem>
}
if(noHiddenRouter.length > 0){ //当子路由只有一个且该子路由的hidden为false或不设置该子路由的hidden时则显示其父路由和下拉的子路由
return (
<SubMenu key={item.url} title={<span><Icon type={item.icon} /><span>{item.name}</span></span>}>
{
noHiddenRouter.map(v => {
return <MenuItem key={v.url}><Link to={v.url} replace>{v.name}</Link></MenuItem>
})
}
</SubMenu>
)
}
}else if(item.children && item.children.length > 1){ //当当前路由有两个及两个以上子路由时,若两个子路由的hidden都为true时则该路由和其子路由全部隐藏
if(item.hidden) return false
let noHiddenRouter = [];
item.children.map(v => {
if(v.hidden){
return <MenuItem key={item.url}><Link to={item.url} replace><Icon type={item.icon} /><span>{item.name}</span></Link></MenuItem>
}else{
noHiddenRouter.push(v)
return true
}
})
if(noHiddenRouter.length > 0){
return (
<SubMenu key={item.url} title={<span><Icon type={item.icon} /><span>{item.name}</span></span>}>
{
noHiddenRouter.map(v => {
return <MenuItem key={v.url}><Link to={v.url} replace>{v.name}</Link></MenuItem>
})
}
</SubMenu>
)
}
}
return true
});
}
render() {
let selectedKey = this.props.location.pathname;
let openKey = "";
for (let menuObj of slideBarConfig) {
if (menuObj.children && menuObj.children.length) {
for (let menuList of menuObj.children) {
if (menuList.url === selectedKey) {
openKey = menuObj.url;
}
}
}
}
let { collapsed, left } = this.state;
return (
<div id='page'>
<Layout>
<Sider collapsible trigger={null} collapsed={collapsed}>
<Menu theme="dark" mode="inline" defaultOpenKeys={[openKey]} selectedKeys={[selectedKey]}>
{this.getSubmenu()}
</Menu>
</Sider>
<Layout className="layout-content" style={{marginLeft: left}}>
<Top toggle={this.toggleCollapsed} collapsed={collapsed} logout={this.logout}/>
<Contents />
<Footer style={{textAlign: 'center'}}>React-Admin ©2019 Created by 小坏 <a target='_blank' href='https://github.com/zhangZhiHao1996/react-admin-master' rel="nofollow me noopener noreferrer">github地址</a></Footer>
</Layout>
</Layout>
</div>
);
}
}
export default Container;
以上代码实现的只是显示和隐藏左侧菜单导航的路由,如果用户直接输入隐藏的导航菜单地址也还是可以访问到具体的页面的,不过那也没办法,总不能删掉隐藏的导航菜单吧,除非用户是真的想搞事情,一般的用户不会这么玩的。
React+Ant Design设置左侧菜单导航路由的显示与隐藏(与权限无关)的更多相关文章
-
react ant design TreeNode——树形菜单笔记
2017-12-04补充说明——树形菜单版本号2.x 设置默认该树形组件展开(默认展开所有树节点) 参考文档的写法: defaultExpandAll={true} //经过测试并不生效, 另外注意 ...
-
React + Ant Design网页,配置
第一个React + Ant Design网页(一.配置+编写主页) 引用博主的另外一篇VUE2.0+ElementUI教程, 请移步: https://blog.csdn.net/u0129070 ...
-
ant design pro (三)路由和菜单
一.概述 参看地址:https://pro.ant.design/docs/router-and-nav-cn 二.原文摘要 路由和菜单是组织起一个应用的关键骨架,我们的脚手架提供了一些基本的工具及模 ...
-
Ant Design Blazor 组件库的路由复用多标签页介绍
最近,在 Ant Design Blazor 组件库中实现多标签页组件的呼声日益高涨.于是,我利用周末时间,结合 Blazor 内置路由组件实现了基于 Tabs 组件的 ReuseTabs 组件. 前 ...
-
【React自制全家桶】一、Webstrom+React+Ant Design+echarts搭建react项目
前言 一.React是Facebook推出的一个前端框架,之前被用于著名的社交媒体Instagram中,后来由于取得了不错的反响,于是Facebook决定将其开源.出身名门的React也不负众望,成功 ...
-
(二)React Ant Design Pro + .Net5 WebApi:前端环境搭建
首先,你需要先装一个Nodejs,这是基础哦.如果没有这方面知识的小伙伴可以在园子里搜索cnpm yarn等关键字,内容繁多,此不赘述,参考链接 一. 简介 1. Ant Design Pro v5 ...
-
django 权限设置 左侧菜单点击显示,面包屑
1.左侧菜单点击显示 就是在点击的时候保留点击的功能 方法. 1.加入新的字段,pid来判断 class Permission(models.Model): """ 权限 ...
-
React / Ant Design Pro 实现Canvas画布实时自适应
如何实现canvas根据父容器进行自适应? Ant Design的组件都提供了强大的自适应能力,为了对齐父组件,镶嵌在Ant Design组件里的canvas也需要能根据父级容器进行自适应的能力,页面 ...
-
react ant design路由配置
最初的时候,只使用了antd中的menu,header和footer都是自己写的组件,在写路由时,总是报如下错误: 相关的路由配置如下: 在网上查的说是组件未暴露出去或者是return 这一行必须有个 ...
随机推荐
-
com.apache.dc.query.Query所属包名apache-common-sid.jar
com.apache.dc.query.Query所属包名apache-common-sid.jar 首先这个类是基于HQL的,好多方法里面要传String clzz, 刚开始我真不知道这个参数传什么 ...
-
Effective C++笔记:构造/析构/赋值运算
条款05:了解C++默默编写并调用哪些函数 默认构造函数.拷贝构造函数.拷贝赋值函数.析构函数构成了一个类的脊梁,只有良好的处理这些函数的定义才能保证类的设计良好性. 当我们没有人为的定义上面的几个函 ...
-
Codeforces Round #354 (Div. 2) C. Vasya and String
题目链接: http://codeforces.com/contest/676/problem/C 题解: 把连续的一段压缩成一个数,对新的数组求前缀和,用两个指针从左到右线性扫一遍. 一段值改变一部 ...
-
[工作积累] Android dynamic library &; JNI_OnLoad
Bionic libc doesn't load dependencies for current .so file (diff from Windows or Linux) so a explici ...
-
linq any()方法实现sql in()方法的效果
public IQueryable<Vsec009ComSecComp> QueryList(Sec009ComSecCompQueryCondition condition) { var ...
-
【Android开源项目分析】android轻量级开源缓存框架——ASimpleCache(ACache)源代码分析
转载请注明出处:http://blog.csdn.net/zhoubin1992/article/details/46379055 ASimpleCache框架源代码链接 https://github ...
-
Asp.Netserver控制发展Grid实现(一个)UI转让
使用Asp.Net办Web开发时间,控制系统提供了,目的,有时很难达到理想的.然后,有几种方法来解决,例如,使用html+js形式,在所需界面的布局的前端,然后通过ajax和其他方式获得的数据.为了实 ...
-
实现基于Haproxy+Keepalived负载均衡高可用架构
1.项目介绍: 上上期我们实现了keepalived主从高可用集群网站架构,随着公司业务的发展,公司负载均衡服务已经实现四层负载均衡,但业务的复杂程度提升,公司要求把mobile手机站点作为单独的服务 ...
-
JAVA 8 函数式接口--Consumer
从JDK8开始java支持函数式编程,JDK也提供了几个常用的函数式接口,这篇主要介绍Consumer接口.文本介绍的顺序依次为: 源码介绍 使用实例 jdk内对Consumer的典型使用 扩展类介绍 ...
-
Robot Framework 内置变量
转自:https://blog.csdn.net/qq_26886929/article/details/53907755 Robot Framework 内部提供了一下直接可用的内置变量 1. 操作 ...