react 路由配置以及封装
1、新建App.tsx文件
import React, { Component } from 'react'
import IsRouter from './router/islogin'
class App extends Component {
render() {
return (
<IsRouter/>
);
}
}
export default App;
IsRouter是用来判断其是否登录的js文件,我通常把它放在router文件夹下,看个人习惯。
2、islogin.jsx内容如下
import React, { Component } from 'react'
import {BrowserRouter as Router,Route} from 'react-router-dom'
import Layout from '../layout/layout'
export default class Islogin extends Component{
// constructor(props) {
// super(props);
// this.state = { };
// }
render(){
return(
<Router>
{/* <Route path="/login" component={Login}/> */}
<Route path="/*" render={()=><Layout/>}/>
</Router>
)
}
}
本项目只是一个模板,因此忽略了登录这块直接展示Laout组件,也就是我们常见的后台管理系统模块。
3、layout页面展示
页面是仿照antd pro后台管理系统案例做的,
import HeaderBar from '../component/Header';
import React, { Component } from 'react'
import {Redirect,Route,Link,Switch } from 'react-router-dom'
import {Layout,Menu} from 'antd';
import router from '../router/router'
import Footer from '../component/Footer'
import logo from '../assets/img/logo192.png';
import 'antd/dist/antd.css';
import './layout.scss'
const {Sider,Content} = Layout;
const { SubMenu } = Menu;
let route = router.map((item)=>{
return item.path;
})
const SliderMenu = ()=>{
let pathname = window.location.pathname;
if(pathname ==='/'){
pathname = '/dashboard/Analysis';
}
let selectedKey = pathname //设置defaultSelectedKeys
let openKey = "/"+ pathname.split("/")[1] //截取二级路由的一级路径,设置defaultOpenKeys
const [openKeys, setOpenKeys] = React.useState([openKey]);
const onOpenChange = (keys:any) => {
const latestOpenKey = keys.find((key:any) => openKeys.indexOf(key) === -1);
if (route.indexOf(latestOpenKey) === -1) {
setOpenKeys(keys);
} else {
setOpenKeys(latestOpenKey ? [latestOpenKey] : []);
}
};
//遍历左侧餐单
const renderMenu = (menus:any)=>{
let Menus = menus.map((item:any)=>{
if(item.routes){
return <SubMenu key={item.path} title={
<span>
{item.icon}
<span>{item.title}</span>
</span>
}>
{renderMenu(item.routes)}
</SubMenu>
}else{
return <Menu.Item key={item.path} icon={item.icon ? item.icon:'' }>
<Link to={item.path}>{item.title}</Link>
</Menu.Item>
}
})
return Menus;
}
return (
<Menu theme="dark" mode="inline"
defaultOpenKeys={ [openKey] }
defaultSelectedKeys={ [selectedKey] }
openKeys={openKeys}
onOpenChange={onOpenChange}
>
{renderMenu(router)}
</Menu>
)
}
class BasicLayout extends Component {
state={
collapsed:false,
defaultOpenKeys: ['/dashboard'], // 默认展开
defaultSelectedKeys: ['/dashboard/Analysis'], // 默认选中
}
//控制左侧菜单收缩
toggle=()=>{
this.setState({
collapsed:!this.state.collapsed
})
}
//渲染路由
forList=(List:any[])=>{
var arr= List.map((item)=>{
if(item.routes){
return item.routes.map((each:any)=>{
return <Route exact key={each.path} path={each.path} component={each.component}></Route>
})
}else{
return <Route exact key={item.path} path={item.path} component={item.component}></Route>
}
})
let newarr:any[] =[];
arr.forEach(item=>{
if(Object.prototype.toString.call(item) === '[object Array]'){
item.forEach((each:any)=>{
newarr.push(each);
})
}else{
newarr.push(item);
}
})
return newarr;
}
componentDidMount(){
}
render() {
let name;
if (!this.state.collapsed) {
name = <span className="name">React管理后台</span>;
}
return (
<Layout>
<Sider trigger={null} collapsible collapsed={this.state.collapsed} style={{ height: '100vh',zIndex:100}} onCollapse={ this.toggle } width={208}>
<div className="logo">
<img src={logo} alt="" className="custom-img"/>
{name}
</div>
<SliderMenu/>
</Sider>
<Layout className="site-layout">
<HeaderBar toggle={this.toggle}></HeaderBar>
<Content
className="site-layout-background"
style={{
height:'auto',
minHeight: 'auto'
}}
>
<div className="ant-pro-grid-content">
<div className="ant-pro-grid-content-children">
<Switch>
{this.forList(router)}
<Redirect from="/*" to="/dashboard/Analysis"></Redirect>
</Switch>
</div>
</div>
</Content>
<Footer/>
</Layout>
</Layout>
);
}
}
export default BasicLayout;
每一个模块代码中可以明确知道是干什么的,具体就不详细说了。
4、router.js
router.js和vue封装的router.js效果差不多,只不过是react需要自己封装。
// import basicLayout from '../layout/layout'
import Analysis from '../page/dashboard/Analysis'
import Monitor from '../page/dashboard/Monitor'
import Workbench from '../page/dashboard/Workbench'
import Personal from '../page/Personal'
import Stepform from '../page/form/Stepform'
import Advanceform from '../page/form/Advanceform'
import Tablelist from '../page/list/Tablelist'
import Basiclist from '../page/list/Basiclist'
import {
OrderedListOutlined,
UserOutlined,
FormOutlined,
SmileOutlined
} from '@ant-design/icons';
let routes=[
{
title:'Dashboard',
path:'/dashboard',
icon: <SmileOutlined/>,
routes:[
{
title:'分析页',
id:'1-2',
path:'/dashboard/Analysis',
component:Analysis
},
{
title:'监控页',
id:'1-1',
path:'/dashboard/Monitor',
component:Monitor
},
{
title:'工作台',
id:'1-3',
path:'/dashboard/Workbench',
component: Workbench
},
]
},
{
title:'表单页',
path:'/form',
icon: <FormOutlined />,
routes:[
{
title:'分布表单',
path:'/form/step-form',
component:Stepform
},
{
title:'高级表单',
path:'/form/advanced-form',
component:Advanceform
},
]
},
{
title:'列表页',
path:'/list',
icon: <OrderedListOutlined />,
// component:Personal
routes:[
{
title:'查询表格',
path:'/list/table-list',
component:Tablelist
},
{
title:'标准列表',
path:'/list/basic-list',
component:Basiclist
}
]
},
{
title:'个人页',
path:'/personal',
icon: <UserOutlined/>,
component:Personal
}
]
export default routes;
这里需要强调一点的是上述代码都是一级路由,如果想配二级路由,那在每一个层级直接配置就行,废话不多说,上案例
{
title:'Dashboard',
path:'/dashboard',
icon: <SmileOutlined/>,
routes:[
{
title:'分析页',
id:'1-2',
path:'/dashboard/Analysis',
component:Analysis,
exact:false, //这个一定得设置成false非严格模式,如果设置成true就会导致页面路由匹配不到页面空白不会报错
//假设这个层级下面还有二级理由analysicdetail
children:[
{
title:'分析详情页',
id:'1-2-1',
path:'/dashboard/Analysis/analysicdetail',
component:Analysicdetail,
exact:true //这个可以设置成严格模式
},
]
},
{
title:'监控页',
id:'1-1',
path:'/dashboard/Monitor',
component:Monitor
},
{
title:'工作台',
id:'1-3',
path:'/dashboard/Workbench',
component: Workbench
},
]
},
接下来在路由渲染的时候修改代码
import config from './router/router'
let router = config.routes.map((item,key)=>{
return <Route exact={item.exact} path={item.path} key={key} render={
props =>{
if(item.children){
return <item.component {...props} routes={item.children} />
}else{
return <item.component {...props} />
}
}
}/>
})
上面是一级路由渲染,二级路由渲染同上面有点类似
//渲染路由
forList=(List)=>{
var arr= List.map((item)=>{
if(item.children){
return item.children.map((each)=>{
return <Route exact={each.exact} key={each.path} path={each.path} component={each.component}></Route>
})
}else{
return <Route exact={each.exact} key={item.path} path={item.path} component={item.component}></Route>
}
})
return arr;
}
componentDidMount(){
let router = this.props.routes;//有点基础的前端应该知道item.children把值传给了routes,那在二级页面上就能够拿到对应导航下的所有路由,不明白的可以打印一下看routers是什么。
this.forList(router);
}
render(){
let routes = this.props;
return (
{
this.forList(routes)//componentDidMount可以不要,效果和render方法渲染的效果相同,只不过为了看起来更加容易理解,两种方式任选一种。
}
)
}