1. 因为 react-router4 没有在提供 onEnter 这样的全局跳转钩子,所以要通过 高阶组件 去处理 来实现一个 路由守卫
2. 按需加载这里我同样使用 高阶组件 来实现
3. 登录成功时 要先获取用户菜单保存到redux中,在登录状态下,刷新页面需要重新获取菜单,并保存到redux中,方便在路由守卫中直接从redux中拿到菜单数据来填充进主体页面路由文件中去。
ps: 只在这里记录一下尝试的核心代码部分,实际效果可在 github 上克隆代码后 运行项目查看
一、路由守卫
守卫 routerComponent.js相关代码
1 import React, { Component } from 'react'; 2 3 import { Route, Redirect } from 'react-router-dom'; 4 5 import { renderRoutes } from 'react-router-config'; 6 7 import {asyncComponent as async} from '@/utils/asyncComponent.js'; 8 9 import store from '@/store/index'; 10 11 import Main from '@/router/main'; 12 13 14 class RouterAuth extends Component { 15 constructor(props) { 16 super(props); 17 18 this.state = { 19 20 }; 21 } 22 23 //根据菜单生成路由文件 24 handleRouters(menu){ 25 let childRouter = []; 26 menu.forEach((item) => { 27 if(!!item.childs){ 28 childRouter = [...childRouter, ...this.handleRouters(item.childs)]; 29 }else{ 30 let component = item.component; 31 let path = item.path; 32 //根据es6module语法,由于import是静态执行,所以不能使用表达式和变量, 33 //解决方法 es6模板字符串 import(`./path/${myFile}.jsx`)。 34 // 注意: 35 // ${myFile}变量前边一定要写一个带"/"的字符串。 36 // ".jsx" 不能写在变量里,要写在字符串里。 37 //目前只能一个页面对应一个js,如何按模块对应js? 38 item.component = async(()=>import(/* webpackChunkName: "[request]" */ `@/${component}.jsx`)); 39 return childRouter.push(item) 40 } 41 }) 42 return childRouter 43 } 44 45 render() { 46 let { location, config } = this.props; 47 let { pathname } = location; 48 console.log(location, config, pathname) 49 50 let token = localStorage.getItem('token'); 51 52 let targetRouterConfig = config.find((item) => item.path === pathname); 53 54 55 //如果是登录状态 56 if(!!token){ 57 //如果进入登录页面,则直接重定向至首页 58 if(pathname === '/login' || pathname === '/'){ 59 return <Redirect to='/home' /> 60 }else{ 61 //如果路由存在 62 if(targetRouterConfig){ 63 //如果是需要登录的或者是404页面则直接进入 64 if(targetRouterConfig.auth || pathname === '/404'){ 65 let { component } = targetRouterConfig; 66 return <Route exact path={pathname} component={component} /> 67 }else{//否则重定向到首页 68 return <Redirect to='/home' /> 69 } 70 }else{ 71 //判断没有设置权限菜单,则根据菜单设置上 72 if(Main[0].routes.length == 0){ 73 let menu = store.getState().user.menu; 74 let menus = this.handleRouters(menu); 75 Main[0].routes = menus; 76 } 77 //如果菜单中包含当前路由,则进入 78 let menuConfig = Main[0].routes.filter((item) => { 79 return item.path === pathname 80 }); 81 if(menuConfig.length != 0){ 82 return renderRoutes(Main); 83 }else{//不包含则进入404 84 return <Redirect to='/404' /> 85 } 86 87 } 88 } 89 }else{ //非登录状态 90 //如果路由存在 91 if(targetRouterConfig){ 92 //如果需要登录,则跳转到登录页 93 if(targetRouterConfig.auth){ 94 return <Redirect to='/login' /> 95 }else{//不需要登录,则正常进入 96 let { component } = targetRouterConfig; 97 return <Route exact path={pathname} component={component} /> 98 } 99 }else{ 100 //路由不存在,直接进入登录页 101 return <Redirect to='/login' /> 102 } 103 } 104 } 105 } 106 107 export default RouterAuth;