个人博客网站制作教程,无二制造 网站升级建设中,网站建设重庆最加科技,腾讯云注册域名后怎么做网站#x1f308;个人主页#xff1a;前端青山 #x1f525;系列专栏#xff1a;React篇 #x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来React篇专栏内容:react后台管理系统(二) 前言
本文档旨在详细说明如何在一个基于React的应用程序中实现左侧菜单… 个人主页前端青山 系列专栏React篇 人终将被年少不可得之物困其一生 依旧青山,本期给大家带来React篇专栏内容:react后台管理系统(二) 前言
本文档旨在详细说明如何在一个基于React的应用程序中实现左侧菜单栏的点击跳转功能并确保在页面刷新后菜单栏能够保持选中状态。通过本文档读者将了解到如何配置路由、创建页面组件、处理编程式跳转、设置重定向和404页面以及如何利用useLocation Hook来保持菜单栏的状态。本文档适合对React和React Router有一定了解的前端开发人员。
目录
前言
8.点击左侧菜单跳转Url地址
9.创建页面对应的组件
9.配置路由
10.渲染路由组件
11.路由的重定向以及404页面
12.刷新页面左侧菜单栏保持选中状态
总结 8.点击左侧菜单跳转Url地址
注意观察Menu组件的属性表找到onClick属性
编程式跳转
// 方式1import {withRouter} from react-router-dom
class App extends Component {render () {return (button onClick { () {this.props.history.push()}}跳转/button)}
}
export default withRouter(App) // 方式2import {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 } themedark modeinline openKeys{openKeys} onOpenChange{onOpenChange} {renderMenus(menus)}{/* Menu.Item key1Option 1/Menu.ItemSubMenu keysub1 icon{MailOutlined /} titleNavigation OneMenu.Item key1Option 1/Menu.ItemMenu.Item key2Option 2/Menu.ItemMenu.Item key3Option 3/Menu.ItemMenu.Item key4Option 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;
ContentclassNamesite-layout-backgroundstyle{{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 } //divpRoute 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 (div404/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 } themedark modeinline openKeys{openKeys} selectedKeys { [pathname] } // onOpenChange{onOpenChange} {renderMenus(menus)}{/* Menu.Item key1Option 1/Menu.ItemSubMenu keysub1 icon{MailOutlined /} titleNavigation OneMenu.Item key1Option 1/Menu.ItemMenu.Item key2Option 2/Menu.ItemMenu.Item key3Option 3/Menu.ItemMenu.Item key4Option 4/Menu.Item/SubMenu */}/Menu);
};
export default SideMenu
总结
本文档通过详细的步骤和示例代码展示了如何在React应用中实现左侧菜单栏的点击跳转功能并确保在页面刷新后菜单栏能够保持选中状态。主要涵盖了以下几个方面
编程式跳转介绍了如何使用useHistory Hook进行编程式跳转。创建页面组件展示了如何创建和配置各个页面组件。配置路由详细说明了如何在路由文件中配置组件和路径。渲染路由组件介绍了如何在布局组件中渲染路由组件。路由的重定向及404页面讲解了如何设置路由重定向和404页面。保持菜单栏选中状态使用useLocation Hook获取当前路径并设置菜单栏的选中状态。
通过本文档的学习能够熟练掌握在React应用中实现左侧菜单栏点击跳转及状态保持的方法从而提升用户体验和开发效率。