react 自定义高阶组件,实现路由拦截,子路由渲染

1、首先我们需要一个高阶组件“RoutingGuard.js”,和router.js(包含所以一级路由的一个数组)文件,在 app.js 中使用 高阶组件

  (1)目录如下

  

 

 

 

 

2、RoutingGuard.js 高阶组件(这里需要注意的是 ('/' + pathname.split('/')[1]) === item.path.replace(/\s*/g,"") ,只检索一级路由

 

import React, { Component } from "react";
import { Route, Redirect } from "react-router-dom";
import { getCookie } from '../utils/common.js'

class FrontendAuth extends Component {
  render() {
    const { routerConfig, location } = this.props;
    console.log(this.props)

    const { pathname } = location;
    console.log( pathname.split('/')[1])

    // 登录成功状态
    const isLogin = getCookie("flwebvpn_admin_sessionid");
    
    // 检索当前 pathname 是否包含,router.js 路面的某个路由
    const targetRouterConfig = routerConfig.find(
      (item) => {
        // 这里为什么使用('/' + pathname.split('/')[1])检索路由,这一步是为了方便使用子路由,这样检索等于只检索一级路由,二级路由不检索
        // 例如:/home/user 这里也会返回 home 组件,如果不想让 /home/user 路由展示home 组件,使其变成非法路由,就像在home组件添加 <Redirect from="/home/*" to="/404"></Redirect>,再或者可以在router.js 里面添加一个是否有子组件的状态,一级路由检索出来之后,判断该路由对象的子组件的状态 是否为true,如果为true返回路由对象,否则判断是否有2级路由有则为非法路由,返回false,没有2级路由返回路由对象
        return ('/' + pathname.split('/')[1]) === item.path.replace(/\s*/g,"")
      }
    );
    
    if (isLogin) {
      // 如果是登陆状态,想要跳转到登陆,重定向到主页
      if (pathname === "/login" || pathname === '/') {
        return <Redirect to="/home" />;
      } else {
        // 如果路由合法,就跳转到相应的路由
        if (targetRouterConfig) {
          return (<Route path={pathname} exact={true} component={targetRouterConfig.component} />);
        } else {
          // 如果路由不合法,重定向到 404 页面
          return <Redirect to="/404" />;
        }
      }
    } else {
      // 没有登录
      if(pathname === '/'){  // 没有登录,默认 / 路由跳转 /login 页面
        return <Redirect to="/login" />;
      } else if (targetRouterConfig && !targetRouterConfig.auth) {  // 合法路由 and (auth:false)该路由不需要登录
        const { component } = targetRouterConfig;
        return <Route exact path={pathname} component={component} />
      } else if (targetRouterConfig && targetRouterConfig.auth) {  // 合法路由 and (auth:false)该路由需要登录
        return <Redirect to="/login" />;
      } else {
        // 非登陆状态下,路由不合法时,重定向至 404
        return <Redirect to="/404" />;
      }
    }
  }
}
export default FrontendAuth

 

 

 

 

 

 3、router.js 包含所有一级路由的对象

import Home from '../page/home/home';
import Login from '../page/login/login.jsx';
import NotFound from '../page/NotFound/NotFound.jsx';

var routes = [
    { path: "/home", name: "home", component: Home, auth: true },
    { path: "/login", name: "login", component: Login, auth: false },
    { path: "/404", name: "NotFound", component: NotFound, auth: false },
]
// auth 是否需要登录
export default routes;

 

 

4、app.js 使用高阶组件

 

import React from 'react';
import { HashRouter as Router,Switch } from "react-router-dom";
import router from './router/router';
import RoutingGuard from './router/RoutingGuard';  // 高阶组件

function App() {
  return (
    <div className="App">
      <Router>
        <Switch>
      // 使用高阶组件,传入router 数组

          <RoutingGuard routerConfig={router} />
        </Switch>
      </Router>
    </div>
  );
}

export default App;

 

5、home 组件实现 子路由

import React from "react";
import { Drawer, NavBar, Toast } from 'antd-mobile';
import './home.less';
import userManagement from '../../components/userManagement/userManagement.jsx';
import Theme from '../../components/theme/theme.jsx';
import roleManagement from '../../components/roleManagement/roleManagement.jsx';
import resourceAdministration from '../../components/resourceAdministration/resourceAdministration.jsx';
import { Route,Redirect,Switch } from "react-router-dom";
import { Button, WingBlank } from 'antd-mobile';
import { delCookie } from "../../utils/common";

export default class home extends React.Component {
    state = {
        docked: false,
        title: 'webVpn'
    }
    onDock = (d) => {
        this.setState({
            [d]: !this.state[d],
        });
    }

    // 导航切换
    NavSelect = (routerPath, index) => {
        // 动画
        this.refs.path.style.top = (document.getElementsByClassName('c-sidebar__link')[0].offsetHeight * index) + 'px';
        // 路由
        this.props.history.push(routerPath);

        setTimeout(() => {
            this.setState({
                docked: false
            })
            // 修改title
            if (this.props.location.pathname === '/home') {
                this.setState({
                    title: '主题'
                })
            } else if (this.props.location.pathname === '/home/userManagement') {
                this.setState({
                    title: '用户管理'
                })
            } else if (this.props.location.pathname === '/home/role') {
                this.setState({
                    title: '角色管理'
                })
            } else if (this.props.location.pathname === '/home/resouce') {
                this.setState({
                    title: '资源管理'
                })
            }
        }, 300);
    }

    componentDidMount() {

        if (this.props.location.pathname === '/home') {
            this.refs.path.style.top = (document.getElementsByClassName('c-sidebar__link')[0].offsetHeight * 0) + 'px';
            this.setState({
                title: '主题'
            })
        } else if (this.props.location.pathname === '/home/userManagement') {
            this.refs.path.style.top = (document.getElementsByClassName('c-sidebar__link')[0].offsetHeight * 1) + 'px';
            this.setState({
                title: '用户管理'
            })
        } else if (this.props.location.pathname === '/home/role') {
            this.refs.path.style.top = (document.getElementsByClassName('c-sidebar__link')[0].offsetHeight * 2) + 'px';
            this.setState({
                title: '角色管理'
            })
        } else if (this.props.location.pathname === '/home/resouce') {
            this.refs.path.style.top = (document.getElementsByClassName('c-sidebar__link')[0].offsetHeight * 3) + 'px';
            this.setState({
                title: '资源管理'
            })
        }
    }

    // 退出登录
    logOut = ()=>{
        delCookie('flwebvpn_admin_sessionid');
        Toast.success('退出成功');
        this.props.history.push('/login');
    }


    render() {
        console.log(`${this.props.match.path}/user`)
        const sidebar = (<div className="navContent">
            <p className="web-font logo">webVpn</p>
            <span className="c-sidebar__title">
                管理员操作
            </span>
            <ul>
                <li className={this.props.location.pathname === '/home' ? 'c-sidebar__link activeNav' : 'c-sidebar__link'} onClick={
                    this.NavSelect.bind(this, '/home', 0)
                }>
                    <i className="iconfont">&#xe91d;</i>
                    <span>主题</span>
                </li>
                <li className={this.props.location.pathname === '/home/userManagement' ? 'c-sidebar__link activeNav' : 'c-sidebar__link'} onClick={
                    this.NavSelect.bind(this, '/home/userManagement', 1)
                }>
                    <i className="iconfont">&#xe610;</i>
                    <span>用户管理</span>
                </li>
                <li className={this.props.location.pathname === '/home/role' ? 'c-sidebar__link activeNav' : 'c-sidebar__link'} onClick={
                    this.NavSelect.bind(this, '/home/role', 2)
                }>
                    <i className="iconfont">&#xe72c;</i>
                    <span>角色管理</span>
                </li>
                <li className={this.props.location.pathname === '/home/resouce' ? 'c-sidebar__link activeNav' : 'c-sidebar__link'} onClick={
                    this.NavSelect.bind(this, '/home/resouce', 3)
                }>
                    <i className="iconfont">&#xe60a;</i>
                    <span>资源管理</span>
                </li>
                <span ref="path"></span>
            </ul>
            <WingBlank style={{ position: 'absolute',left: '0',right:'0',bottom: '50px' }}>
                <Button size="large" onClick={ this.logOut }>退出登录</Button>
            </WingBlank>
        </div>);

        return (
            <div className="home" style={{ height: '100%' }}>
                <Drawer
                    className="my-drawer"
                    style={{ minHeight: document.documentElement.clientHeight }}
                    contentStyle={{ color: '#A6A6A6', textAlign: 'center' }}
                    sidebarStyle={{ border: '1px solid #ddd' }}
                    sidebar={sidebar}
                    docked={this.state.docked}
                    touch={true}
                    dragToggleDistance={30}
                >
                    <NavBar
                        mode="light"
                        icon={
                            <i className="iconfont">&#xeaff;</i>
                        }
                        onLeftClick={() => this.onDock('docked')}
                        rightContent={[]}
                    >
                        <p className="web-font NavTitle">{this.state.title}</p>
                    </NavBar>
                    {/* 子路由 */}
                    <Switch>
                        <Route path='/home' exact component={Theme}></Route>
                        <Route path='/home/userManagement' exact component={userManagement}></Route>
                        <Route path='/home/role' exact component={roleManagement}></Route>
                        <Route path='/home/resouce' exact component={resourceAdministration}></Route>
                        {/* /home/*: /home下的子路由路由不合法时跳转404页面 */}
                        <Redirect from="/home/*" to="/404"></Redirect>
                    </Switch>
                </Drawer>
            </div>
        )
    }
}

 

 

大功告成

有什么不足的地方,还请大佬指出

posted @ 2021-09-13 13:41  男孩亮亮  阅读(831)  评论(0编辑  收藏  举报