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

 

 

大功告成

有什么不足的地方,還請大佬指出


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM