我们一般在做类似于后台管理系统时,一般都会有两个甚至多个角色用户,这时就需要根据用户的身份来动态定义路由规则,以及用户登录权限判断
routeConstant.js
import loadableComponent from '@/common/loadable';
import LoginComponent from "@/page/login/Login";
import HomeComponent from '@/page/home/Home';
// loadableComponent是实现懒加载的组件,在此处暂不做详细讨论,代码在下面
const UserComponent = loadableComponent(() => import('@/page/home/user/User'));
const UserListComponent = loadableComponent(() => import('@/page/home/user/userList/UserList'));
const AddUserComponent = loadableComponent(() => import('@/page/home/user/addUser/AddUser'));
const DeviceComponent = loadableComponent(() => import('@/page/home/device/Device'));
const DeviceListComponent = loadableComponent(() => import('@/page/home/device/deviceList/DeviceList'));
// name值为角色权限路由的标识符,相同的name将会当做同一条路由配置进行权限控制
const routeList = () => {
return [
{
path: "/home",
component: HomeComponent,
name: "home",
needLogin: true,
children: [
{
path: "/home/user", component: UserComponent, name: "user", needLogin: true, children: [
{ path: "/home/user", component: UserListComponent, name: "userList", needLogin: true, children: [] },
{ path: "/home/user/adduser", component: AddUserComponent, name: "adduser", needLogin: true, children: [] },
]
},
{
path: "/home/device", component: DeviceComponent, name: "device", needLogin: true, children: [
{ path: "/home/device", component: DeviceListComponent, name: "deviceList", needLogin: true, children: [] }
]
},
],
},
{ path: "/login", component: LoginComponent, name: "login", needLogin: false, children: [] },
]
};
export default routeList;
loadable.js
import React from "react";
import Loadable from 'react-loadable';
import { Spin } from "antd";
const loadableComponent = (component) => {
return Loadable({
loader: component,
loading: () => <span>loading………</span>
})
}
export default loadableComponent;
app.js同级目录创建store文件夹,分别创建store.js;reducer.js;actions.js
store.js
import { createStore, applyMiddleware } from "redux";
import reducer from "./reducer";
export default createStore(reducer, applyMiddleware());
reducer.js
import { combineReducers } from "redux";
import option from '@/util/routeConstant';
// 内部使用,不必导出
function setRoute(names, routelist) {
for (let index = 0; index < routelist.length; index++) {
var element = routelist[index];
if (element) {
if (names.includes(element.name)) {
delete routelist[index];
}
setRoute(names, element.children);
}
};
return routelist;
}
function routeOption(state = option(), action) {
switch (action.type) {
case 'SET_ROUTE_OPTION':
let names = action.names;
if (typeof names === 'string') {
names = [names];
}
setRoute(names, state);
return state;
case 'RESET_ROUTE_OPTION':
console.log( option());
return option();
default:
return state
}
}
export default combineReducers({
routeOption
})
actions.js
// 通过name删除路由配置
function setRouteOption(names) {
return {
type:"SET_ROUTE_OPTION",
names:names,
}
}
// 重置路由配置
function resetRouteOption() {
return {
type:"RESET_ROUTE_OPTION",
}
}
export {
setRouteOption,
resetRouteOption
}
最后在index.js中导入使用
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import * as serviceWorker from './serviceWorker';
import { Provider } from "react-redux";
import store from "./store/store";
ReactDOM.render(
<Provider store={store}>
<App store={store}/>
</Provider>
, document.getElementById('root'));
serviceWorker.unregister();
routeOption.js
import React from "react";
import { HashRouter, Route, Redirect, Switch, Link } from "react-router-dom";
import { connect } from 'react-redux';
class routeOption extends React.Component {
constructor(props) {
super(props);
}
islogin = () => {
// 在这里做登录判断
return sessionStorage.getItem(token) ? true : false;
}
// 渲染Route组件
renderRoute = (routeList) => {
return <Switch>
<Route path="/" exact render={() => <Redirect to="/home/user" />}></Route>
{
routeList.map((item, index) => {
return <Route
key={index}
path={item.path}
exact={
item.children.length > 0 ? false : true
}
render={props =>
// 先判断是否需要登录,不需要的话直接渲染对应组件
(item.needLogin
?
this.islogin()
?
(<item.component {...props} >
// 使用递归渲染下层路由
{item.children.length > 0 && this.renderRoute(item.children)}
</item.component>)
:
<Redirect to="/login" />
:
(<item.component {...props} ></item.component>)
)
} />
})
}
<Route path="*" exact render={() => <span>你访问的页面丢失了</span>} />
</Switch>
}
render() {
return (
<HashRouter>
{
this.renderRoute(this.props.propsrouteList)
}
</HashRouter>
);
}
}
// 将redux中的路由信息导入致props
export default connect(state => {
return {
propsrouteList: state.routeOption
}
},null)(routeOption);
App.js
import React from 'react';
import RouteOption from "./routeOption";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {}
}
render() {
return (
<div className="App">
<RouteOption />
</div>
);
}
}
export default App;
现在,你可以在你的项目中的任何地方,通过name来删除用户没有权限查看的路由,
比如作为和login同级的所有页面的父级页面:home.js,登录成功后跳转的页面,在这里做这件事再合适不过了
import React, { Component } from 'react';
import { setRouteOption } from '@/store/actions';
import { connect } from 'react-redux';
class HomeComponent extends Component {
constructor(props) {
super(props);
this.state = {}
}
componentDidMount() {
// 在这里请求当前用户可查看的列表
// 例:这个用户不能查看name为adduser和device对应的页面
const deleteRoute = ['adduser','device'];
this.props.setRouteOption(deleteRoute);
}
render() {
return (
{this.props.children}
)
}
}
export default connect(null, dispatch => {
return {
setRouteOption: (names) => {
dispatch(setRouteOption(names))
}
}
})(HomeComponent);
实际情况中发现,删除用户不可查看的路由信息后,用户更换角色账号再次登录时导致上次删除的信息没有恢复,这就用到了在redux中已经等待许久的resetRouteOption上场了;
登陆成功后重置路由规则
import React from 'react';
import { connect } from 'react-redux';
import { resetRouteOption } from '@/store/actions';
class LoginComponent extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
// 登录请求
loginRequest = () => {
// 登陆成功后重置路由规则致初始状态
this.props.resetRouteOption();
}
render() {
return (
<div className="login-component">
<button onClick={loginRequest}>登录</button>
</div>
)
}
}
export default connect(null, dispatch => {
return {
resetRouteOption: () => {
dispatch(resetRouteOption());
}
}
})(LoginComponent);
以上代码有些冗余,仅作参考
期望大佬轻喷,心情好指点一二,定当洗耳恭听