• React-RouterV6+AntdV4实现Menu菜单路由跳转


    React-RouterV6 + AntdV4实现Menu菜单路由跳转,采用子路由嵌套的方式

    两种实现方式:

    方式一:编程式跳转

    使用useNavigate()

    方式二:NavLink链接式

    主页

    配置路由和主页

    App.js

    import {
      Routes,
      Route,
      Navigate,
      useLocation
    } from 'react-router-dom'
    import Home from './pages/Home';
    import Main from './pages/Main';
    import User from './pages/User';
    import Auth from './pages/Auth';
    
    function App() {
      // 获取浏览器url
      const location = useLocation()
      const { path } = location
      console.log(path);
      return (
        
          {/* 重定向到主页 */}
          } />
          {/* 主页及其子路由 */}
          } >
            {/* url为/home时主动触发二级路由 */}
            } />
            } />
            } />
          
        
      );
    }
    
    export default App;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    Home/index.js

    react-router-dom的Outlet组件,类似于Vue中的router-view,在Outlet处会渲染任何匹配到的子路由组件。

    import React from 'react';
    import { Breadcrumb, Layout } from 'antd';
    import '../../assets/css/layout.css';
    import { LaptopOutlined, NotificationOutlined, UserOutlined } from '@ant-design/icons';
    import { Outlet } from 'react-router-dom'
    import SiderLeft from '../../components/SiderLeft.js';
    import TopHeader from '../../components/TopHeader';
    const { Header, Content, Sider } = Layout;
    
    export default class Home extends React.Component {
        constructor(props) {
            super(props);
            this.state = {};
        }
        // 生命周期函数
        componentDidMount() {
            console.log('componentDidMount');
        }
        componentWillUnmount() {
            console.log('componentWillUnmount');
        }
    
        render() {
            return (
                
                    {/* 头部 */}
                    
    {/* 左侧导航栏 */} { position: 'fixed', left: 0, top: 64, bottom: 0 }} > {/* 渲染左侧菜单组件 */} {/* 右边区域 */} { position: 'relative', right: 0, top: 64, marginLeft: 200, padding: '0 24px 24px', }} > { margin: '16px 0', }} > Home List App { padding: 24, margin: 0, minHeight: 280, }} > {/* 渲染子路由 匹配到子路由时,用子路由的组件替换此处内容*/} {/* 类似Vue中的router-view */}
    ) } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79

    一、编程式跳转

    编程式跳转的方式使用react-router-dom中的useNavigate方法,传入url路径即可进行页面跳转。

    **注意:**useNavigate不能在类组件中使用,如果你非要在类组件中使用,可以使用高阶组件,对类组件进行一个包裹,让原始类组件拥有useNavigate功能。(函数组件中使用useNavigate请自行实现)

    Menu/SiderLeft.js

    import { Menu } from 'antd';
    import React from 'react';
    import { LaptopOutlined, NotificationOutlined, UserOutlined } from '@ant-design/icons';
    // 高阶组件,包裹useNavigate()功能
    import WidthUseNavigate from './withComponents/WithUseNavigate';
    
    class SiderLeft extends React.Component {
        constructor(props) {
            super(props);
            this.state = {
                items: [{
                    key: "/home",
                    icon: React.createElement(UserOutlined),
                    label: "概览"
                }, {
                    key: "/home/user",
                    icon: React.createElement(UserOutlined),
                    label: "用户管理",
                    children: [{
                        key: "/home/user/list",
                        label: "成员管理"
                    }, {
                        key: "/home/user/auth",
                        label: "权限设置"
                    }, {
                        key: "sub23",
                        label: "菜单三"
                    }, {
                        key: "sub24",
                        label: "菜单四"
                    }, {
                        key: "sub25",
                        label: "菜单五"
                    }]
                }]
            };
        }
    
        click = (e) => {
            console.log(e);
            console.log(e.key);
            //注意this指向问题,采用箭头函数this就指向当前组件
            this.props.to(e.key);
        }
    
        openChange() {
            console.log('OpenChange');
        }
        render() {
            return (
                {
                        height: '100%',
                        borderRight: 0,
                    }}
                    items={this.state.items}
                    onOpenChange={() => this.openChange()}
                    onClick={this.click}
                />
            )
        }
    }
    // 使用高阶组件包裹当前类组件
    const NavigateCompont = WidthUseNavigate(SiderLeft);
    // 导出包裹后的类组件
    export default NavigateCompont;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    高阶组件,包裹useNavigate()功能

    widthUseNavigate.js

    import { useNavigate } from 'react-router-dom'
    // 高阶组件包装useNavigate()功能
    // 原因:类组件中无法使用useNavigate(),会报错
    // React Hook "useNavigate" cannot be called in a class component.
    function widthUseNavigate(WrapCompontent) {
      // 设置别名
      WrapCompontent.displayName = `widthUseNavigate${getDisplayName(WrapCompontent)}`
      return function NavigateCompont() {
        const navigate = useNavigate()
        // 给传入的组件新增一个to方法,传给原始组件的props,在原始组件中通过this.props.to(参数)使用
        return 
      }
    }
     
    // 别名
    function getDisplayName(WrapCompontent) {
      return WrapCompontent.displayname || WrapCompontent.name || 'Component'
    }
     
    export default widthUseNavigate
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    二、链接式跳转

    在Menu组件的items中将label的值设置为主页,菜单显示“主页”,同时具备链接跳转功能。

    Menu/SiderLeft.js

    import { Menu } from 'antd';
    import React from 'react';
    import { LaptopOutlined, NotificationOutlined, UserOutlined } from '@ant-design/icons';
    import { NavLink as Link } from 'react-router-dom';
    
    export default class SiderLeft extends React.Component {
        constructor(props) {
            super(props);
            this.state = {
                items: [{
                    key: "/home",
                    icon: React.createElement(UserOutlined),
                    label: 概览
                }, {
                    key: "/home/user",
                    icon: React.createElement(UserOutlined),
                    label: "用户管理",
                    children: [{
                        key: "/home/user/list",
                        label: 成员管理
                    }, {
                        key: "/home/user/auth",
                        label: 权限设置
                    }, {
                        pass...
                    }]
                }]
            };
        }
    
        openChange() {
            console.log('OpenChange');
        }
        render() {
            return (
                {
                        height: '100%',
                        borderRight: 0,
                    }}
                    items={this.state.items}
                    onOpenChange={() => this.openChange()}
                />
            )
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    三、实现效果

    两种方式都能实现点击左侧菜单,右侧内容区显示不同组件。

    Main/index.js

    import React from 'react';
    export default class Main extends React.Component {
        constructor(props) {
            super(props);
            this.state = {};
        }
        render() {
            return (
                // React.Fragment一般跟在return后面,用来包裹元素,之前一般会用div进行包裹
                // Fragment相比于div的好处是在dom中不会增加额外节点,也可以直接简写为<>
                
                    
    主内容区
    ) } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    User/index.js

    import React from 'react';
    export default class User extends React.Component {
        constructor(props) {
            super(props);
            this.state = {};
        }
        render() {
            return (
                
                    
    用户列表
    ) } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    Auth/index.js

    import React from 'react';
    export default class Auth extends React.Component {
        constructor(props) {
            super(props);
            this.state = {};
        }
        render() {
            return (
                
                    
    权限设置
    ) } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    输入任何未匹配到路由的url,重定向到主页,默认渲染Main组件

    点击“成员管理”,右侧内容展示区渲染User组件

    点击“权限管理”,右侧内容展示区渲染Auth组件

    先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦

  • 相关阅读:
    DI的几种注入方式
    C++ Reference: Standard C++ Library reference: C Library: cwchar
    【没用的小知识又增加了--CCS】
    Windows常用快捷键与查询命令
    傅里叶变换的四种形式
    MMDetection系列 | 5. MMDetection运行配置介绍
    单片机——用单片机控制一个灯闪烁
    AM5-DB低压备自投装置在河北冠益荣信科技公司洞庭变电站工程中的应用
    天龙八部门派采集任务坐标
    C#里TcpListener的阻塞式服务器
  • 原文地址:https://blog.csdn.net/m0_66557301/article/details/126113977