React动态路由;路由权限控制;通过角色身份删除对应的路由规则

React动态路由;路由权限控制;通过角色身份删除对应的路由规则

  • 使用场景
  • 实现思路
    • 将全局路由整合
    • 通过react-redux实现全局修改
    • 路由渲染组件
    • 最后一步
    • 大功告成
    • 重置路由规则
    • 写在最后

使用场景

我们一般在做类似于后台管理系统时,一般都会有两个甚至多个角色用户,这时就需要根据用户的身份来动态定义路由规则,以及用户登录权限判断

实现思路

  1. 整合全局路由
  2. 使用react-redux实现全局控制

将全局路由整合

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;

通过react-redux实现全局修改

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);

写在最后

以上代码有些冗余,仅作参考
期望大佬轻喷,心情好指点一二,定当洗耳恭听

你可能感兴趣的:(React动态路由;路由权限控制;通过角色身份删除对应的路由规则)