react后台管理系统(二)

​🌈个人主页:前端青山
🔥系列专栏:React篇
🔖人终将被年少不可得之物困其一生

依旧青山,本期给大家带来React篇专栏内容:react后台管理系统(二)

前言

本文档旨在详细说明如何在一个基于React的应用程序中实现左侧菜单栏的点击跳转功能,并确保在页面刷新后菜单栏能够保持选中状态。通过本文档,读者将了解到如何配置路由、创建页面组件、处理编程式跳转、设置重定向和404页面,以及如何利用useLocation Hook来保持菜单栏的状态。本文档适合对React和React Router有一定了解的前端开发人员。

目录

前言

8.点击左侧菜单跳转Url地址

9.创建页面对应的组件

9.配置路由

10.渲染路由组件

11.路由的重定向以及404页面

12.刷新页面左侧菜单栏保持选中状态

总结

8.点击左侧菜单跳转Url地址

注意观察Menu组件的属性表,找到onClick属性

编程式跳转

// 方式1
import {withRouter} from 'react-router-dom'
class App extends Component {render () {return (<button onClick = { () => {this.props.history.push()}}>跳转</button>)}
}
export default withRouter(App)
// 方式2
import {withRouter} from 'react-router-dom'
function App (props) {return (<button onClick = { () => {props.history.push()}}>跳转</button>)
}
export default withRouter(App)
​
// 方式3 ---- useHistory https://reactrouter.com/web/api/Hooks/usehistory
import { useHistory } from 'react-router-dom'
function App () {const history = useHistory() // 不可以在组件的内部事件中调用return (<button onClick = { () => {history.push()}}>跳转</button>)
}
export default App
import React from 'react'
import { Menu } from 'antd';
import menus from '../../router/menus'
import { useHistory } from 'react-router-dom'
const { SubMenu } = Menu;
​
// submenu keys of first level
const keyArr = []
menus.forEach(item => { // 只需要一级菜单项即可keyArr.push(item.path)
})
// const rootSubmenuKeys = ['sub1', 'sub2', 'sub4'];
const rootSubmenuKeys = keyArr
​
const SideMenu = () => {// 用来 编程式跳转const history = useHistory()const [openKeys, setOpenKeys] = React.useState([]);
​const onOpenChange = keys => {const latestOpenKey = keys.find(key => openKeys.indexOf(key) === -1);if (rootSubmenuKeys.indexOf(latestOpenKey) === -1) {setOpenKeys(keys);} else {setOpenKeys(latestOpenKey ? [latestOpenKey] : []);}};const renderMenus = (menus) => {return menus.map(item => {// 判断当前的选项有没有子菜单if (item.children) { // 有子级菜单return (<SubMenu key={ item.path } icon={ item.icon } title={item.title}>{/* 递归调用自身,渲染多级菜单 */}{ renderMenus(item.children) }</SubMenu>)} else {// path具有唯一性,key也具有唯一性// 为了后续操作方便,此时建议将path作为遍历的key值return <Menu.Item key={ item.path } icon = { item.icon }>{ item.title }</Menu.Item>}})}const changeUrl = ({ key }) => {// console.log(key) // 为什么在渲染菜单栏时 把 item.path 置为 key属性// console.log(item)// 编程式跳转 props.history.pushhistory.push(key)}return (<Menu onClick = { changeUrl } theme="dark" mode="inline" openKeys={openKeys} onOpenChange={onOpenChange} >{renderMenus(menus)}{/* <Menu.Item key="1">Option 1</Menu.Item><SubMenu key="sub1" icon={<MailOutlined />} title="Navigation One"><Menu.Item key="1">Option 1</Menu.Item><Menu.Item key="2">Option 2</Menu.Item><Menu.Item key="3">Option 3</Menu.Item><Menu.Item key="4">Option 4</Menu.Item></SubMenu> */}</Menu>);
};
​
export default SideMenu

9.创建页面对应的组件

点击左侧菜单跳转至页面

9.配置路由

路由文件menus 中 配置组件

import React from 'react'
import { HomeOutlined,PictureOutlined,NotificationOutlined,UsergroupDeleteOutlined,SwitcherOutlined
} from '@ant-design/icons'
import Home from './../views/home/Index'
const menus = [{title: '系统首页',path: '/home',key: '0-0',icon: <HomeOutlined />,component: Home},{title: '轮播图管理',path: '/banner',key: '0-1',icon: <PictureOutlined />,children: [{title: '轮播图列表',path: '/banner/list',key: '0-1-0',component: React.lazy(() => import('./../views/banner/Index'))},{title: '添加轮播图',path: '/banner/add',key: '0-1-1',component: React.lazy(() => import('./../views/banner/Add'))},]},{title: '首页数据管理',path: '/homeData',key: '0-2',icon: <NotificationOutlined />,children: [{title: '秒杀列表',path: '/homeData/skill',key: '0-2-0',component: React.lazy(() => import('./../views/homeData/Skill'))
​},{title: '推荐列表',path: '/homeData/recommend',key: '0-2-1',component: React.lazy(() => import('./../views/homeData/Recommend'))}]},{title: '用户管理',path: '/users',key: '0-3',icon: <UsergroupDeleteOutlined />,children: [{title: '用户列表',path: '/users/list',key: '0-3-0',component: React.lazy(() => import('./../views/users/List'))},{title: '管理员列表',path: '/users/adminList',key: '0-3-1',component: React.lazy(() => import('./../views/users/AdminList'))}]},{title: '商品管理',path: '/pro',key: '0-4',icon: <SwitcherOutlined />,children: [{title: '商品列表',path: '/pro/list',key: '0-4-0',component: React.lazy(() => import('./../views/pro/List'))},{title: '筛选商品',path: '/pro/search',key: '0-4-1',component: React.lazy(() => import('./../views/pro/Search'))}]}
]
export default menus

10.渲染路由组件

创建路由组件 layout/main/RouterView

Layout/main/index.jsx

import RouterView from './RouterView';
​<ContentclassName="site-layout-background"style={{margin: '24px 16px',padding: 24,minHeight: 280,}}>{/* Content */}<RouterView></RouterView></Content>
​
export default App

渲染路由

import React, { Suspense } from 'react'
import { Switch, Route } from 'react-router-dom'
import { Spin } from 'antd';
import menus from './../../router/menus'
function RouterView() {const renderRoute = (menus) => {return menus.map(item => {if (item.children) {// 递归调用return renderRoute(item.children)} else {return <Route path = { item.path } key = { item.path } component = { item.component } />}})}return (<Suspense fallback = { <Spin /> }><Switch>{/* <Route path="" component={} /> */}{renderRoute(menus)}</Switch></Suspense>)
}
​
export default RouterView

递归调用的函数,如果写成jsx代码形式,在jsx代码中 调用回调函数会发生什么情况

以下代码仅供参考--不要在项目中使用

import React, { Suspense, Fragment } from 'react'
import { Switch, Route } from 'react-router-dom'
import { Spin } from 'antd';
import menus from './../../router/menus'
import Home from './../../views/home/Index'
import UserList from './../../views/users/List'
function RouterView() {const renderRoute = (menus) => {return menus.map(item => {if (item.children) {// 递归调用return renderRoute(item.children) // return <Fragment key={item.path}>{ renderRoute(item.children) }</Fragment>} else {return <Route path = { item.path } key = { item.path } component = { item.component } />}})}return (<Suspense fallback = { <Spin /> }>{/* Switch 内 如果写 非 Route 或者是 非 Redirect元素,哪怕其中包含了Route也只有第一个元素会生效*/}<Switch>{/* <Route path="" component={} /> */}{renderRoute(menus)}<div ><Route path="/home111" component = { Home } /></div><p><Route path="/user111" component = { UserList } />  </p></Switch></Suspense>)
}
​
export default RouterView

11.路由的重定向以及404页面

修改menus.js,添加redirect选项

import React from 'react'
import { HomeOutlined,PictureOutlined,NotificationOutlined,UsergroupDeleteOutlined,SwitcherOutlined
} from '@ant-design/icons'
import Home from './../views/home/Index'
const menus = [{title: '系统首页',path: '/home',key: '0-0',icon: <HomeOutlined />,component: Home},{title: '轮播图管理',path: '/banner',key: '0-1',icon: <PictureOutlined />,redirect: '/banner/list', // ***************************children: [{title: '轮播图列表',path: '/banner/list',key: '0-1-0',component: React.lazy(() => import('./../views/banner/Index'))},{title: '添加轮播图',path: '/banner/add',key: '0-1-1',component: React.lazy(() => import('./../views/banner/Add'))},]},{title: '首页数据管理',path: '/homeData',key: '0-2',icon: <NotificationOutlined />,redirect: '/homeData/skill',// ***************************children: [{title: '秒杀列表',path: '/homeData/skill',key: '0-2-0',component: React.lazy(() => import('./../views/homeData/Skill'))
​},{title: '推荐列表',path: '/homeData/recommend',key: '0-2-1',component: React.lazy(() => import('./../views/homeData/Recommend'))}]},{title: '用户管理',path: '/users',key: '0-3',icon: <UsergroupDeleteOutlined />,redirect: '/users/list',// ***************************children: [{title: '用户列表',path: '/users/list',key: '0-3-0',component: React.lazy(() => import('./../views/users/List'))},{title: '管理员列表',path: '/users/adminList',key: '0-3-1',component: React.lazy(() => import('./../views/users/AdminList'))}]},{title: '商品管理',path: '/pro',key: '0-4',icon: <SwitcherOutlined />,redirect:"/pro/list",// ***************************children: [{title: '商品列表',path: '/pro/list',key: '0-4-0',component: React.lazy(() => import('./../views/pro/List'))},{title: '筛选商品',path: '/pro/search',key: '0-4-1',component: React.lazy(() => import('./../views/pro/Search'))}]}
]
export default menus

创建404页面 views/error/NotFound/Inex.jsx

import React from 'react'
​
function NotFound() {return (<div>404</div>)
}
​
export default NotFound
​
import React, { Suspense } from 'react'
import { Switch, Route, Redirect } from 'react-router-dom'
import { Spin } from 'antd';
import menus from './../../router/menus'
import NotFound from './../../views/error/NotFound/Index'
function RouterView() {const renderRoute = (menus) => {return menus.map(item => {if (item.children) {// 递归调用return renderRoute(item.children)} else {return <Route path = { item.path } key = { item.path } component = { item.component } />}})}const renderRedirect = (menus) => {return menus.map(item => {if (item.redirect) {return <Redirect exact key={ item.key } from = { item.path } to = { item.redirect } />} else {return null}})}return (<Suspense fallback = { <Spin /> }><Switch>{/* <Route path="" component={} /> */}{renderRoute(menus)}{// 渲染重定向以及404页面renderRedirect(menus)}<Redirect exact from = "/" to="/home" /><Route component = { NotFound } /></Switch></Suspense>)
}
​
export default RouterView
​

12.刷新页面左侧菜单栏保持选中状态

使用 useLocation 获取到地址栏中的地址,解构得到pathname属性,设置展开菜单项 openKeys为 字符串类型的数组

设置 selectedKeys 为pathname。-------- 注意数据类型

import React from 'react'
import { Menu } from 'antd';
import menus from '../../router/menus'
import { useHistory, useLocation } from 'react-router-dom' // =+++++++++++
const { SubMenu } = Menu;
​
// submenu keys of first level
const keyArr = []
menus.forEach(item => { // 只需要一级菜单项即可keyArr.push(item.path)
})
// const rootSubmenuKeys = ['sub1', 'sub2', 'sub4'];
const rootSubmenuKeys = keyArr
​
const SideMenu = () => {// 获取地址栏中的地址const location = useLocation() // =+++++++++++const { pathname } = location // /banner/list // =+++++++++++console.log(location)// 用来 编程式跳转const history = useHistory()// 设置默认打开哪一项  ---- 参数是 string[] ['/banner']// // =+++++++++++const [openKeys, setOpenKeys] = React.useState(['/' + pathname.split('/')[1] ]);
​const onOpenChange = keys => {const latestOpenKey = keys.find(key => openKeys.indexOf(key) === -1);if (rootSubmenuKeys.indexOf(latestOpenKey) === -1) {setOpenKeys(keys);} else {setOpenKeys(latestOpenKey ? [latestOpenKey] : []);}};const renderMenus = (menus) => {return menus.map(item => {// 判断当前的选项有没有子菜单if (item.children) { // 有子级菜单return (<SubMenu key={ item.path } icon={ item.icon } title={item.title}>{/* 递归调用自身,渲染多级菜单 */}{ renderMenus(item.children) }</SubMenu>)} else {// path具有唯一性,key也具有唯一性// 为了后续操作方便,此时建议将path作为遍历的key值return <Menu.Item key={ item.path } icon = { item.icon }>{ item.title }</Menu.Item>}})}const changeUrl = ({ key }) => {// console.log(key) // 为什么在渲染菜单栏时 把 item.path 置为 key属性// console.log(item)// 编程式跳转 props.history.pushhistory.push(key)}return (<Menu onClick = { changeUrl } theme="dark" mode="inline" openKeys={openKeys} selectedKeys = { [pathname] } // =+++++++++++onOpenChange={onOpenChange} >{renderMenus(menus)}{/* <Menu.Item key="1">Option 1</Menu.Item><SubMenu key="sub1" icon={<MailOutlined />} title="Navigation One"><Menu.Item key="1">Option 1</Menu.Item><Menu.Item key="2">Option 2</Menu.Item><Menu.Item key="3">Option 3</Menu.Item><Menu.Item key="4">Option 4</Menu.Item></SubMenu> */}</Menu>);
};
​
export default SideMenu

总结

本文档通过详细的步骤和示例代码,展示了如何在React应用中实现左侧菜单栏的点击跳转功能,并确保在页面刷新后菜单栏能够保持选中状态。主要涵盖了以下几个方面:

  1. 编程式跳转:介绍了如何使用useHistory Hook进行编程式跳转。
  2. 创建页面组件:展示了如何创建和配置各个页面组件。
  3. 配置路由:详细说明了如何在路由文件中配置组件和路径。
  4. 渲染路由组件:介绍了如何在布局组件中渲染路由组件。
  5. 路由的重定向及404页面:讲解了如何设置路由重定向和404页面。
  6. 保持菜单栏选中状态:使用useLocation Hook获取当前路径,并设置菜单栏的选中状态。

通过本文档的学习,能够熟练掌握在React应用中实现左侧菜单栏点击跳转及状态保持的方法,从而提升用户体验和开发效率。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/887042.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【学习笔记】AD智能PDF导出(装配文件)

2.下一步“NEXT” 3.选择文件名称&#xff0c;下一步“NEXT” 4.可选导出原材料的BOM表 右键选择装配图“Create Assembly Drawings” 5.可以双击下图方框&#xff0c;或者右键需要编辑的标题&#xff0c;选择“Properties”&#xff0c;勾选如下图 6.装配文件&#xff0c;添加…

在win10环境部署opengauss数据库(包含各种可能遇到的问题解决)

适用于windows环境下通过docker desktop实现opengauss部署&#xff0c;请审题。 文章目录 前言一、部署适合deskdocker的环境二、安装opengauss数据库1.配置docker镜像源2.拉取镜像源 总结 前言 注意事项&#xff1a;后面docker拉取镜像源最好电脑有科学上网工具如果没有科学上…

如何构建高效的接口自动化测试框架?

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 在选择接口测试自动化框架时&#xff0c;需要根据团队的技术栈和项目需求来综合考虑。对于测试团队来说&#xff0c;使用Python相关的测试框架更为便捷。无论选…

AI Prompt Engineering

AI Prompt Engineering 简介 Prompt Engineering, 提示工程&#xff0c;是人工智能领域的一项技术&#xff0c;它旨在通过设计高效的提示词&#xff08;prompts&#xff09;来优化生成式 AI&#xff08;如 GPT、DALLE 等&#xff09;的输出。提示词是用户与生成式 AI 交互的核…

【bug】使用transformers训练二分类任务时,训练损失异常大

使用transformers训练二分类任务时&#xff0c;训练损失异常大 问题分析 问题 training_loss异常大&#xff0c;在二分类损失中&#xff0c;收敛在1~2附近&#xff0c;而eval_loss却正常&#xff08;小于0.5&#xff09; 分析 参考&#xff1a; Bug in gradient accumulation…

基于SpringBoot实现的城镇保障性住房管理系统(代码+论文)

&#x1f389;博主介绍&#xff1a;Java领域优质创作者&#xff0c;阿里云博客专家&#xff0c;计算机毕设实战导师。专注Java项目实战、毕设定制/协助 &#x1f4e2;主要服务内容&#xff1a;选题定题、开题报告、任务书、程序开发、项目定制、论文辅导 &#x1f496;精彩专栏…

springboot基于SpringBoot的社区居民诊疗健康管理系统

摘 要 社区居民诊疗健康管理系统的建设强化了社区医疗服务与居民之间的联系&#xff0c;优化了健康服务供给&#xff0c;提高了医疗资源的利用效率。它不仅有助于提升居民的健康素养和自我管理能力&#xff0c;也是推动实现全民健康信息化、构建以人为本的健康服务体系的重要步…

VSCode 间距太小

setting->font family 使用&#xff1a;Consolas, Courier New, monospace 字体

IntelliJ+SpringBoot项目实战(九)--整合Thymyleaf模版引擎

一、Thymeleaf 基本介绍 Thymeleaf是一款模板引擎产品&#xff0c;是一款优秀的面向JAVA的XML/XHTML/HTML5页面模板&#xff0c;具有丰富的标签语言和函数。因此&#xff0c;在使用SpringBoot开发前端网页&#xff0c;经常选择Thymeleaf。 在前后端分离框架流行的今天&a…

Python中常用的函数介绍

Python中常用的几种函数 1、input函数 input()函数&#xff1a;主要作用是让用户输入某个内容并接收它。 #输入你的年龄 >>> age input("my age is :") my age is :20 执行代码后输入年龄&#xff0c;年龄被存放到age变量中&#xff0c;执行print后终端会…

【动手学深度学习Pytorch】1. 线性回归代码

零实现 导入所需要的包&#xff1a; # %matplotlib inline import random import torch from d2l import torch as d2l import matplotlib.pyplot as plt import matplotlib import os构造人造数据集&#xff1a;假设w[2, -3.4]&#xff0c;b4.2&#xff0c;存在随机噪音&…

亿咖通科技应邀出席微软汽车行业智享会,分享ECARX AutoGPT全新实践

11月14日&#xff0c;全球出行科技企业亿咖通科技&#xff08;纳斯达克股票代码&#xff1a;ECX&#xff09;应邀于广州参加由微软举行的汽车行业智享会&#xff0c;揭晓了亿咖通科技对“AI定义汽车”时代的洞察与技术布局&#xff0c;分享了亿咖通科技汽车垂直领域大模型ECARX…

鸿蒙开发学习|Promise的介绍与在鸿蒙中的使用

Promise的介绍与在鸿蒙中的使用 异步编程 学习Promise的开始,我们要先了解异步编程 一般代码的执行是单线程的机制,就是按次序执行,执行完一个任务后,再执行下一个,如果我们在页面加载的同时时候执行一个请求,拿到数据后映射到界面上,这时我们就需要异步操作来执行这个请求 异…

第二课 Model模型资源导入设置检查与优化

上期我们学习了最简单的audio音效的优化&#xff0c;接下来我们继续model模型资源的优化&#xff0c;我将汇总各路大神关于模型优化的思路和方法供你和我学习。 首先我们还是要把我们优化的目标重申一遍&#xff1a; 优化的目标 1.文件体积尽可能小 2.内存占用尽可能小 3.…

小米路由器用外网域名访问管理界面

本文在Redmi AX3000 (RA81)设置&#xff0c;其他型号路由器的管理界面端口可能各不相同。 开始之前需要保证路由器SSH功能正常&#xff0c;如果没有SSH可以参考这里。 1. 给WAN口开放80端口 可以通过下载mixbox的firewall插件或者其他防火墙插件开放端口。 2. 把域名解析到路…

一次需升级系统的wxpython安装(macOS M1)

WARNING: The scripts libdoc, rebot and robot are installed in /Users/用户名/Library/Python/3.8/bin which is not on PATH. 背景&#xff1a;想在macos安装Robot Framework &#xff0c;显示pip3不是最新&#xff0c;更新pip3后显示不在PATH上 参看博主文章末尾 MAC系统…

Leetcode 求根节点到叶节点数字之和

使用深度优先搜索 DFS 来做 我提供的代码使用的是 深度优先搜索&#xff08;DFS&#xff0c;Depth-First Search&#xff09; 算法。以下是具体的算法思想和实现步骤的解释&#xff1a; 算法思想 树的路径代表数字&#xff1a; 树中每条从根节点到叶子节点的路径可以看作一个整…

IDEA:2023版远程服务器debug

很简单&#xff0c;但是很多文档没有写清楚&#xff0c;wocao 一、首先新建一个远程jvm 二、配置 三、把上面的参数复制出来 -agentlib:jdwptransportdt_socket,servery,suspendn,address5005 四、然后把这串代码放到服务器中&#xff08;这里的0.0.0.0意思是所有IP都能访问&a…

计算机毕业设计 | SpringBoot+vue汽车资讯网站 汽车购买咨询管理系统(附源码+论文)

1&#xff0c;绪论 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理汽车资讯网站的相关信息成为必然…

RedHat系统配置静态IP

1、执行nmtui命令进入字符配置界面如下图所示 2、选择编辑连接进入 3、选择编辑进入后&#xff0c;将IPv4设置为手动模式后&#xff0c;选择显示后进行ip地址、网关、DNS的配置&#xff0c;配置完成后选择确定退出编辑 4、进入主界面后选择启用连接进入后&#xff0c;选择启用&…