[原创]React+Ant Design设置左侧菜单导航路由的显示与隐藏(与权限无关)

最近在学习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;

以上代码实现的只是显示和隐藏左侧菜单导航的路由,如果用户直接输入隐藏的导航菜单地址也还是可以访问到具体的页面的,不过那也没办法,总不能删掉隐藏的导航菜单吧,除非用户是真的想搞事情,一般的用户不会这么玩的。

原文地址:https://www.cnblogs.com/tnnyang/p/10516160.html

时间: 2024-09-30 09:55:38

[原创]React+Ant Design设置左侧菜单导航路由的显示与隐藏(与权限无关)的相关文章

仿淘宝左侧菜单导航栏纯Html + css 写的

这俩天闲来没事淘宝逛了一圈看到淘宝的左侧导航菜单做的是真心的棒啊,一时兴起,查了点资料抓了几个图片仿淘宝写了个css,时间紧写的不太好,大神勿喷,给小白做个参考 废话不多说先来个效果图 接下来直接上代码,图片没法传,只能直接放代码下边,辛苦点一张一张扣去吧?? HTML部分 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd

【react自制全家桶】一、Webstrom+React+Ant Design+echarts搭建react项目

前言 一.React是Facebook推出的一个前端框架,之前被用于著名的社交媒体Instagram中,后来由于取得了不错的反响,于是Facebook决定将其开源.出身名门的React也不负众望,成功成为当前最火热的三大前端框架之一.相比于Angular,React更加轻量.而相对于另一个轻量级前端框架Vue来说,React虽然学习和使用起来难度稍微大一些,但是React的社区相对来说人气更旺,而且在移动端的开发上面,大名鼎鼎的React Native更是尽显优势,在代码性能上要好过Vue框架.

左侧菜单导航

关注" web前端学习部落22群"群号 领取前端免费学习资料及工具! <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>左边导航</title> <style> *{margin:0;padding:0;/*background: #8d90ef;#0387e0*/text-

Ecshop(二次开发) - 后台添加左侧菜单导航

1.链接地址:修改 admin\includes\inc_menu.php 文件. $modules['17_syn_data']['view_syn']        =    'synchronization_cat_data.php?act=main'; 2.语言文字:修改 languages\zh_cn\admin\common.php 文件. /* 菜单分类部分 */ $_LANG['17_syn_data'] = '数据同步管理'; /*同步数据 */ $_LANG['view_sy

采用React+Ant Design组件化开发前端界面(一)

react-start 基础知识 1.使用脚手架创建项目并启动 ? 1.1 安装脚手架: npm install -g create-react-app ? 1.2 使用脚手架创建项目: create-react-app antd-start-demo antd-start-demo为项目名. ? 1.3 启动 npm start 2.npm转换为yarn ? 2.1 安装yarn: npm install -g yarn ? 2.2 获取yarn当前的镜像源: yarn config get

vue实现点击左侧菜单,右侧跟着显示隐藏

1 <template> 2 <div class="mainMaterial"> 3 <div class="chooseItem"> 4 <div class="navMenus"> 5 <ul> 6 <li v-for="(item,index) in items" :key="index" :class="{active:i

代码中设置 actionbar 上home等图标显示跟隐藏

今天在做项目的时候,遇到了一个问题,就是要把home在代码中动态显示跟隐藏.现在把方法记录如下 我们可以使用 setDisplayOptions(mask, mask); 来设置home按钮显示的,它的具体用法如下 (1)如果只有一个参数,那么它就是直接设定显示项, 如, int options = DISPLAY_SHOW_HOME | DISPLAY_USE_LOGO: setDisplayOptions(options); 那么,actionbar就会显示home跟log按钮,也就是,里面

js监听网页页面滑动滚动事件,实现导航栏自动显示或隐藏

/** * 页面滑动滚动事件 * @param e *///0为隐藏,1为显示var s = 1; function scrollFunc(e) { // e存在就用e不存在就用windon.event e = e || window.event;// 先判断是什么浏览器 if (e.wheelDelta) { // 浏览器IE,谷歌 if (e.wheelDelta > 0) {//当滑轮向上滚动时// console.log("滑轮向上滚动"); if (s == 0) {

使用Facebook的create-react-app脚手架快速构建React开发环境(ant.design,redux......)

 create-react-app是来自于Facebook出品的零配置命令行工具,能够帮你自动创建基于Webpack+ES6的最简易的React项目模板 1:首先在webstorm中新建一个项目 2:倘若不是最新版本的npm   ,   安装最新版本npm     npm install npm @latest 3: 安装项目中常用的相关的配置 yarn add react-redux redux redux-thunk react-router-dom thunk [email protect