在使用 Vue 或者 Angular 的时候,框架提供了路由守卫功能,用来在进入某个路有前进行一些校验工作,如果校验失败,就跳转到 404 或者登陆页面,比如 Vue 中的
函数:
[JavaScript]
纯文本查看
复制代码
1 2 3 4 5 6 | ...router.beforeEach(async(to, from, next) => { const toPath = to.path; const fromPath = from.path;})... |
在之前的版本中,React Router 也提供了类似的 onEnter 钩子,但在 React Router 4.0 版本中,取消了这个方法。React Router 4.0 采用了声明式的组件,路由即组件,要实现路由守卫功能,就得我们自己去写了。
如果不使用路由守卫,Router 组件是这样子的:
[JavaScript]
纯文本查看
复制代码
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 | import * as React from 'react';import { HashRouter,Switch,Route,Redirect } from 'react-router-dom';import { HomePage } from '../pages/home/home.page';import { LoginPage } from '../pages/login/login.page';import { ErrorPage } from '../pages/error/error.page';export const Router = () => ( <HashRouter> <Switch> <Route path="/" exact component={HomePage}/> <Route path="/login" exact component={LoginPage}/> <Route path="/home" exact component={HomePage}/> <Route path="/404" exact component={ErrorPage}/> <Redirect to="/404" /> </Switch> </HashRouter>); |
上面的 Router 组件,包含了三个页面:
- 登陆
- 主页
- 404 页面
- 根路由
- 登陆路由
- 主页路由
- 404 路由
以上是一个基本的路由定义,可以在登陆/主页和 404 页面之间来回跳转,但也有一些问题:
- 非登陆状态下,可以直接跳转到主页
- 登陆状态下,也可以输入 /login 路由跳转到登录页
- 非登陆状态下,无法直接跳转到主页,如果在非登陆状态下进行主页跳转,需要重定向至登陆路由
- 登陆状态下,无法跳转至登录页,如果在登陆状态下进行登陆页跳转,需要重定向至主页路由
- 在每个组件中,根据 props 上的 history 对象来进行跳转
- 进行全局的路由守卫处理
在 React Router 4.0 中,没有再像之前的版本那样,提供 onEnter 这样的全局跳转钩子,因此要通过高阶组件的方式去处理。
下面是我的实现方式,首先,准备一份路由表,包含了路由的地址,组件以及是否需要权限校验:
[JavaScript]
纯文本查看
复制代码
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | import { HomePage } from '../pages/home/home.page';import { LoginPage } from '../pages/login/login.page';import { ErrorPage } from '../pages/error/error.page';interface routerConfigModel { path:string, component?:any, auth?:boolean}export const routerConfig:routerConfigModel[] = [ { path:'/', component:HomePage, auth:true, },{ path:'/home', component:HomePage, auth:true, },{ path:'/login', component:LoginPage, },{ path:'/404', component:ErrorPage }]; |
将
设置为
,表示该路由需要权限校验。
然后,定义
组件,该组件是经过高阶组件包装后的结果:
[JavaScript]
纯文本查看
复制代码
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 | import * as React from 'react';import { HashRouter,Switch } from 'react-router-dom';import { FrontendAuth } from '../components/frontend-auth/frontend-auth.component'import { routerConfig } from './router.config'export class Router extends React.Component{ render(){ return( <HashRouter> <Switch> <FrontendAuth config={routerConfig} /> </Switch> </HashRouter> ); }} |
所有的路由跳转,都交给
高阶组件代理完成。下面是
组件的实现:
[JavaScript]
纯文本查看
复制代码
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | import * as React from 'react';import { Route,Redirect } from 'react-router-dom';import { propsModel } from './frontend-auth.model'export class FrontendAuth extends React.Component<any,propsModel>{ render(){ const { location,config } = this.props; const { pathname } = location; const isLogin = localStorage.getItem('__config_center_token') // 如果该路由不用进行权限校验,登录状态下登陆页除外 // 因为登陆后,无法跳转到登陆页 // 这部分代码,是为了在非登陆状态下,访问不需要权限校验的路由 const targetRouterConfig = config.find((v:any) => v.path === pathname); if(targetRouterConfig && !targetRouterConfig.auth && !isLogin){ const { component } = targetRouterConfig; return <Route exact path={pathname} component={component} /> } if(isLogin){ // 如果是登陆状态,想要跳转到登陆,重定向到主页 if(pathname === '/login'){ return <Redirect to='/' /> }else{ // 如果路由合法,就跳转到相应的路由 if(targetRouterConfig){ return <Route path={pathname} component={targetRouterCon |