react后台管理系统路由配置:
大概需求:
假设:dashboard文件放的是整个页面,分为导航,和侧边栏,中间内容栏;导航和侧边每个路由都需要,将相关的路由页面都放到中间内容共栏就可以。
1、分为两部分大文件、login登入页面
,/ 转到到dashboard,
这样分的好处是,不用跳转到一个页面就判断有没有登入。这里进行统一判断,如果没有登入 ,其他以/ 开头的页面都会跳转到login中。
一旦登入后就跳转到dashboard页面中,这个页面有导航栏,和侧边栏,这两个是公用内容,哪里都用的上。下面部分就是动态会变的。
一、文件:router.js路由配置
做判断,登入了就允许看所有页面,没有登入就打到登入页面
import React, { Component } from 'react' //引入核心
import { //引入路由相关配置
HashRouter, // 构建 hash 路由, #/home #/login === ( Vue mode:hash )
// BrowserRouter,// 构建 history 路由 /home /login === ( Vue mode:history )
Redirect, //重定向
Route, //路由坑
Switch //模糊匹配,箱单与Switch判断语句
} from 'react-router-dom'
//-------blog 自定义组件-------------------------
import Login from '../views/login/Login' //111、登入页面
import DashBoard from '../views/dashboard/DashBoard'//222、设置为/ 的页面,整个页面结构都在这个文件,名字随便取
export default class Router extends Component {
render() {
return (
<HashRouter> //哈希路由
<Switch> //判断路由,先匹配登入页面,匹配上就brack出去
<Route path="/login" component={Login}/>
路由拦截--三目 ————用render箭头函数形式,做判断,是否有token,有就说明登入,能进入到后台页面,没有就打回登入页面
<Route path="/" render={()=>
localStorage.getItem("token")?<DashBoard/>:<Redirect to="/login"/>
} />
</Switch>
</HashRouter>
)
}
}
2、配置完成后就直接在App.js中引入,让他加载这个路由页面就可以了
文件:App.js配置使用
import React from 'react'; //引入核心react
import BlogRouter from './router' //引入router路由配置文件
//根组件
class App extends React.Component{
render(){
return <BlogRouter/> //直接return出去,变成jsx文件供页面使用
}
}
export default App;
3、 dashboard文件用于配置整个页面结构及路由:( 斜杠 / 页面 )
注:真实工作中权限这里不用自己做判断,我们只负责循环操作
//引入相关的路由及核心
import React, { Component } from 'react'
import { Route, Redirect, Switch } from 'react-router-dom'
import Home from '../home/Home'
import Users from '../usermanage/Users'
import SideMenu from './SideMenu' //组件的侧边栏,用antd-UI搭建
import TopHeader from './TopHeader' //组件的导航栏,用antd-UI搭建
import './index.css'
//antd组件库的配置
import { Layout } from 'antd';
import Create from '../article-manage/Create'
const { Content } = Layout; //解构
export default class DashBoard extends Component {
render() {
let { roleType } = JSON.parse(localStorage.getItem("token")) //将token结构出来
return (
<Layout>
{/* 自定义的sidemenu */}
<SideMenu></SideMenu> //侧边栏
<Layout className="site-layout">
<TopHeader></TopHeader> //组件导航栏
<Content //以下全是组件内容区的配置,
className="site-layout-background"
style={{
margin: '24px 16px',
padding: 24,
minHeight: 'auto',
}}
>
<Switch> //开始相关的路由配置
{/* home路由 */}
<Route path="/home" component={Home} />
{/* 用户权限-用户列表 */} //这个判断是根据token的内容,判断登入后用户的权限,如果登入用户权限大于3的话就渲染这个路由组件,如小于,就不渲染,这个用户就没有权限看着列表
{roleType >= 3 ?
<Route path="/user-manage/users" component={Users} />
:
null
}
{/* 权限管理-权限列表,角色列表 */}
{
roleType >= 3 ?
<Route path="/right-manage" component={Manage} />
: null
}
{/* 文章管理- 文章列表 文章分类 */}
<Route path="/article-manage/list" component={List} />
<Route path="/article-manage/preview/:myid" component={Preview} exact /> //动态组件的详情页面
<Route path="/article-manage/create" component={Create}/>
<Redirect from="/" to="/home" exact /> //重定向到home页面
<Route path="*" component={NotFound} /> //上面的都匹配不到,设置 “ * ”后随便在地址栏乱输都会匹配404组件
</Switch>
</Content>
</Layout>
</Layout>
)
}
}
渲染路由的第二种情况:(后端返回的数据直接渲染)
import React, { Component } from 'react' //引入核心
import {Route,Redirect,Switch} from 'react-router-dom'//引入路由
import newList from '@/views/index' //引入后端数据
import { Layout } from 'antd' //antd
const { Content } = Layout;//antd
export default class Contents extends Component { //组件
constructor(props) {
super(props)
this.state = {
}
}
forList = (newList) =>{ //定义函数,接收后端数据
// console.log(newList)
return newList.map((item) =>{ //循环
if(item.children) { //判断是否有孩子,有就继续循环
return item.children.map((item) =>{ //循环孩子数据路由
return <Route exact key={item.id} path={item.path} component={item.component}></Route>
})
}else{//如果没有孩子就直接循环
return <Route exact key={item.id} path={item.path} component={item.component}></Route>
}
})
}
render () {
return (
<Content
className="site-layout-background"
style={{
margin: '24px 16px',
padding: 24,
minHeight: '100%',
}}
>
<Switch>//保留模糊匹配
{this.forList(newList)} //调用上面定义的函数,将后端数据传递过去用于渲染路由
<Redirect from="/*" to="/home"></Redirect> //路由重定向
</Switch>
{/* Content */}
</Content>
)
}
}
二、侧边栏配置:(路由跳转)
1、先配置假数据用于做侧边栏的循环:(工作中是后端返回)
list.js文件:
const MyData = [
{//一级菜单需要的参数
title:"首页",
icon:UserOutlined,
permission:1, //权限判断
path:'/home' //设置的好处:1、可以用来跳转页面,2、可以用来配置下拉菜单的默认下来项
},
{
title:"用户管理",
icon:VideoCameraOutlined,
permission:3,
path:'/user-manage',
children:[ //二级菜单的配置
{
title:"用户列表",
icon:UserDeleteOutlined ,
permission:3,
path:"/user-manage/users"
}
]
},
]
export default MyData //抛出去
配置侧边栏:
用antd-UI框架布局侧边栏
defaultSelectedKeys
:组件库提供设置菜单高亮的属性
defaultOpenKeys
:组件库提供设置菜单默认展开效果,key需要和后端返回的数据路径一致
注:递归调用时经典
import React, { Component } from 'react' //引入react核心
import MenuArr from '../../router/list.js'//引入上面定义的假数据
import { Layout, Menu } from 'antd';
import { withRouter } from 'react-router'; //引入高阶组件
import {connect} from 'react-redux' //引入react-redux
const { Sider } = Layout; //解构
const { SubMenu } = Menu;
class SideMenu extends Component { //组件
state = {
collapsed: false
}
//1、自己封装渲染函数,遍历侧边栏
renderMenu = (menus)=>{ //BBB
let {roleType} = JSON.parse(localStorage.getItem("token"))
//2、roleType 当前登录用户的roleType(就是用户权限,从token中拿出来做判断,权限越高看的越多
return menus.map(item=>{
//3、提示:判断当前登录的用户的角色值(roleType),跟当前要渲染的侧边栏项需要的角色值进行对比
if(item.children && roleType >= item.permission){ //4、判断是否有孩子参数,有就渲染二级标题,并且判断登入用户的权限是不是大于标题数据的权限,大于就渲染,小于就隐藏(就是数据中定义的permission)
return <SubMenu key={item.path} title={ //重:将每个渲染的标题都设置key(就是数据中定义的path="/home")用于做编程试导航和菜单高亮
<span>
<item.icon/>
<span>{item.title}</span>
</span>
}>
{
//递归用法
this.renderMenu(item.children) //重:7、下面还有children在继续递归渲染,(就不需要每次都去做循环渲染)
}
</SubMenu>
}else{
if( item.permission > roleType){ //6、判断登入的权限是否大于当前标题数据的权限,大于就显示,小于就隐藏。
return null
}
return ( //5、如果没有children孩子数据,就直接渲染一级标题,menu
<Menu.Item key={item.path} icon={<item.icon />}>重:将每个渲染的标题都设置key(就是数据中定义的path="/home")用于做编程试导航和菜单高亮
{item.title}
</Menu.Item>
)
}
})
}
handleChangePage = (obj)=>{ //AAA
// console.log(obj)
// 高阶组件提供
this.props.history.push(obj.key)//key路由对应的路径,进行点击每一个标题的时候,条状到响应的路由去
}
render() {
// console.log(this.props) //拿到此时路径
let selectedKey = this.props.location.pathname //设置defaultSelectedKeys
let openKey = "/"+this.props.location.pathname.split("/")[1] //截取二级路由的一级路径,设置defaultOpenKeys
return (
<Sider trigger={null} collapsible collapsed={this.props.isCollapsed}>
{/* <div className="logo" /> */}
{
/*
andt组件库提供:defaultSelectedKeys :高亮显示谁?//从编程试导航中结构出来path来,给到这个属性
defaultOpenKeys://初始展开的 SubMenu 菜单项 key 数组 (前提是渲染标题的时候,key要和解构出来的path相对应,不然初始化展开不起作用)
*/
}
<Menu theme="dark" mode="inline" defaultSelectedKeys={[selectedKey]} defaultOpenKeys={[openKey]}
onClick ={this.handleChangePage} //AAA
//点击 MenuItem 调用此函数,会传递点击的是具体的哪一个值过去,就包含数据的path
>
{ //BBBB
this.renderMenu(MenuArr) //调用上面抽离的函数,渲染侧边栏,传递的值就是引入的假数据
}
</Menu>
</Sider>
)
}
}
// connec拿到了store, store.getState()
const mapStateToProps = state => {
// console.log(state)
return {
name:"kerwin",
a:1,
isCollapsed:state.isCollapsed
} //函数返回值 ,就是将来往sideMeun 组件传来的属性
}// 映射redux 状态==>当前组件属性
export default connect(mapStateToProps)(withRouter(SideMenu))