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"></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"></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"></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"></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"></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> ) } }
大功告成
有什么不足的地方,還請大佬指出