此文为个人学习记录文章,若有不足,请勿吐槽。多多指教
目的:只需按需求配置路由树route,然后在需要渲染的地方引入路由组件,即可实现包括子路由在内的层级渲染,子路由的第一个路由配置默认为首次渲染所需的路由,并且包含各层路由的权限认证。权限认证通过后访问对应页面,反之,跳转登录页面。若已登录,但手动使路由跳转到登录页,则会重定向到首页。
实现效果图一(初始效果):红框位置为对应路由所渲染的位置。
示例:
一级路由位置:对应路由为:‘/’,对应页面为:“index.jsx”
二级路由位置:对应路由为:‘/index1’,对应页面为:“index1.jsx”
二级路由位置:对应路由为:‘/index1/index7’,对应页面为:“index7.jsx”
其中 /index1 为 /的子路由,且在路由树中的位置处于第一个, /index1/index7同理。
实现效果图二(未登录状态):点击按钮“第三个页面”,重定向到 登录页
实现效果图三(登录状态): 点击按钮“第三个页面”,页面渲染
代码:
app.js
import './App.css';
import React,{Suspense} from 'react'
import { Provider } from 'react-redux';
import LoginIndex from './component/loginAndRegist/index'
import {routerMap} from './route/index'
import store from './reducers/store'
import { BrowserRouter as Router, HashRouter, Route, Link, Switch, Redirect, withRouter, Prompt } from 'react-router-dom'
import FrontendAuth from './route/requireCredentials2';
function App() {
// return <Routes />
return (
<div className="App">
<Provider store={store}>
{/* <React.StrictMode> */}
{/* <Router forceRefresh={false}>
{routes}
</Router> */}
{/* </React.StrictMode> */}
<Suspense fallback={<div>loading...</div>}>
<Router>
<Switch>
<FrontendAuth index="1"></FrontendAuth>
</Switch>
</Router>
</Suspense>
</Provider>
</div>
);
}
export default App;
route.js
路由树:其中level表示该路由处于第几级路由。auth:表示是否需要权限认证
import React,{lazy}from 'react'
import Login from './../component/loginAndRegist/login'
import Regist from './../component/loginAndRegist/regist'
import Index from './../component/loginAndRegist/index'
// import Index1 from './../component/loginAndRegist/index1'
// import Index2 from './../component/loginAndRegist/index2'
// import Index3 from './../component/loginAndRegist/index3'
import Err from './../component/test/err'
export const routeList=[
{
path:'/',
component:lazy(() => import('@/component/loginAndRegist/index')),
level:1,//对应路由组件上的index。表示当前路由在整个路由树中的层级
child:[
{
path:'/index1',
component:lazy(() => import('@/component/loginAndRegist/index1')),
level:2,
child:[
{
path:'/index1/index7',
level:3,
component:lazy(() => import('@/component/loginAndRegist/index7')),
}
]
}, {
path:'/index2',
level:2,
component:lazy(() => import('@/component/loginAndRegist/index2')),
}, {
path:'/index3',
level:2,
component:lazy(() => import('@/component/loginAndRegist/index3')),
child:[
{
path:'/index3/index4',
level:3,
component:lazy(() => import('@/component/loginAndRegist/index4')),
auth:true
}, {
path:'/index3/index5',
level:3,
component:lazy(() => import('@/component/loginAndRegist/index5')),
}, {
path:'/index3/index6',
level:3,
component:lazy(() => import('@/component/loginAndRegist/index6')),
auth:true
},
]
},
]
},{
path:'/login',
component:Login,
level:1
},{
path:'/regist',
component:Regist,
level:1
},{
path:'/err',
component:lazy(() => import('@/component/test/err')),
level:1
}
]
requireCredentials2.js
路由验证组件,验证逻辑在这里面实现
/**
* 监听路由变化,结合redux中是否登录,进行权限控制路由转变
*/
import React , {Fragment}from 'react'
import { connect } from 'react-redux'
import { Route, withRouter, Redirect } from 'react-router-dom'
import { routeList } from './route'
class FrontendAuth extends React.Component {
constructor(props) {
super(props);
}
render() {
const { routerConfig, location, match } = this.props;
const { pathname } = location;
const isLogin = (this.props.userMes.flag && this.props.userMes.flag != "") ? true : false;//判断是否登录的标志
var data = [];
var resultFlag = false;
var index = this.props.index;
// 将路由的第一个路由作为默认路由
function getFirstChildToData(arr,array=[]){
if(Array.isArray(arr)&&arr.length>0){
var lin = {};
if (arr[0]['path']) lin['path'] = arr[0]['path'];
if (arr[0]['component']) lin['component'] = arr[0]['component'];
if (arr[0]['exact']) lin['exact'] = arr[0]['exact'];
if (arr[0]['strict']) lin['strict'] = arr[0]['strict'];
if (arr[0]['child']) lin['child'] = arr[0]['child'];
if (arr[0]['auth']) lin['auth'] = arr[0]['auth'];
if (arr[0]['level']) lin['level'] = arr[0]['level'];
lin['index'] = true;
array.push(lin);
if(arr[0]['child'])getFirstChildToData(arr[0]['child'],array);
}
}
function findRoute(arr) {
var result = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i]['path'] == pathname) {
resultFlag = true;
var lin = {};
if (arr[i]['path']) lin['path'] = arr[i]['path'];
if (arr[i]['component']) lin['component'] = arr[i]['component'];
if (arr[i]['exact']) lin['exact'] = arr[i]['exact'];
if (arr[i]['strict']) lin['strict'] = arr[i]['strict'];
if (arr[i]['child']) lin['child'] = arr[i]['child'];
if (arr[i]['auth']) lin['auth'] = arr[i]['auth'];
if (arr[i]['index']) lin['index'] = arr[i]['index'];
if (arr[i]['level']) lin['level'] = arr[i]['level'];
result.push(lin);
if(arr[i]['child'])getFirstChildToData(arr[i]['child'],result)
return result;
} else if (arr[i]['child']) {
var res = findRoute(arr[i]['child']);
if(res){
var lin = {};
if (arr[i]['path']) lin['path'] = arr[i]['path'];
if (arr[i]['component']) lin['component'] = arr[i]['component'];
if (arr[i]['exact']) lin['exact'] = arr[i]['exact'];
if (arr[i]['strict']) lin['strict'] = arr[i]['strict'];
if (arr[i]['child']) lin['child'] = arr[i]['child'];
if (arr[i]['auth']) lin['auth'] = arr[i]['auth'];
if (arr[i]['index']) lin['index'] = arr[i]['index'];
if (arr[i]['level']) lin['level'] = arr[i]['level'];
return result.concat(lin).concat(res);
}
}
}
}
// 从路由树中找到匹配的路由,将需要被渲染的路由转换成数组,数组的顺序即为需要渲染的顺序
data = findRoute(routeList);
/***
* 若当前路由未在路由树中找到,则跳转到指定页面
*/
if (!resultFlag) {
return <Redirect to="/err" />;
}
var target = data[parseInt(index) - 1];
if(!(target&&(target.level+''===index+''))){
return <Redirect to="/err" />;
}
if (isLogin) {
// 如果是登陆状态,想要跳转到登陆,重定向到主页
if (pathname === "/login") {
return <Redirect to="/" />;
} else {
// 如果路由合法,就跳转到相应的路由
if (target) {
return target.index?<Route component={target.component} index />:<Route path={target.path} component={target.component}/>
} else {
// 如果路由不合法,重定向到 404 页面
return <Redirect to="/err" />;
}
}
} else {
// 非登陆状态下,当路由合法时且需要权限校验时,跳转到登陆页面,要求登陆
if(target&&target.auth&&target.auth==true){
return <Redirect to="/login" />;
}else if(target&&((target.auth&&target.auth==false)||!target.auth)){
if(target)return target.index?<Route component={target.component} index />:<Route path={target.path} component={target.component}/>
else return <Fragment></Fragment>;
}else{
console.log(target)
return <Redirect to="/err" />;
}
}
}
}
// 将 store 中的数据作为 props 绑定到组件上
const mapStateToProps = (state) => {
return {
userMes: state.auth
}
}
// 将 action 作为 props 绑定到组件上。
const mapDispatchToProps = (dispatch) => {
return {
// userAction:bindActionCreators(userAction,dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(withRouter(FrontendAuth))
index.jsx
“第一个按钮” 对应的页面。FrontendAuth组件 对应requireCredentials2.js,其中它的参数index必须与路由树的“level”对应。子路由想在哪渲染,就在哪添加上这个组件就行
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from "redux"
import { Route, Link , Redirect } from 'react-router-dom'
import * as userAction from '../../action/userAction'
import Index1 from './index1'
import Index2 from './index2'
import index3 from './index3'
import FrontendAuth from '../../route/requireCredentials2'
import './login.css'
class Index extends Component {
constructor(props) {
super(props);
// console.log(this.props.match.path)
}
render() {
const routerMap = [
<Route index path="/index/index1" component={Index1}></Route>,
<Route exact strict path="/index/index2" component={Index2}></Route>,
<Route exact strict path="/index/index3" auth="true" component={index3}></Route>,
<Redirect to="/err"></Redirect>
]
return (
<div className="bigBox">
<div className="switchBox">
<div className="box">
<Link to="/index1" className="loginBtn">第一个页面</Link>
<Link to="/index2" className="loginBtn">第二个页面</Link>
<Link to="/index3" className="loginBtn">第三个页面(权限验证)</Link>
<Link to="/login" className="loginBtn">跳转到登录页</Link>
<Link to="/regist" className="loginBtn">跳转到注册页</Link>
<Link to="/err" className="loginBtn">跳转到404</Link>
</div>
<div className="loginState">登录状态:{this.props.userMes.flag}</div>
<div className="loginState">商品信息:{this.props.shopMes.name}</div>
{/* <Switch>
<Route exact strict path="/index" component={Index2}></Route>,
<Route exact strict path="/index/index3" auth="true" component={index3}></Route>
<Redirect to="/err"></Redirect>
</Switch> */}
<FrontendAuth index="2"></FrontendAuth>
</div>
</div>
)
}
}
// 将 store 中的数据作为 props 绑定到组件上
const mapStateToProps = (state) => {
return {
userMes: state.auth,
shopMes: state.shop
}
}
// 将 action 作为 props 绑定到组件上。
const mapDispatchToProps = (dispatch) => {
return {
userAction: bindActionCreators(userAction, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Index)
index1.jsx
“第一个按钮” 对应的页面,属于index.jsx的子页面;FrontendAuth组件 对应requireCredentials2.js,其中它的参数index必须与路由树的“level”对应。子路由想在哪渲染,就在哪添加上这个组件就行
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from "redux"
import * as userAction from '../../action/userAction'
import FrontendAuth from '@/route/requireCredentials2'
import './login.css'
class index1 extends Component {
constructor(props) {
super(props);
console.log(this.props.match.path)
}
render() {
return (
<div className="bigBox">
我是主页的第一个页面
<FrontendAuth index="3"></FrontendAuth>
</div>
)
}
}
// 将 store 中的数据作为 props 绑定到组件上
const mapStateToProps = (state) => {
return {
userMes: state.auth,
shopMes: state.shop
}
}
// 将 action 作为 props 绑定到组件上。
const mapDispatchToProps = (dispatch) => {
return {
userAction: bindActionCreators(userAction, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(index1)