admin管理员组文章数量:1634852
目录
- 前言
- 项目目录
- 阶段一
- 阶段二
- 阶段三
- 阶段四
- 参考
前言
路由守卫是开发中很常用的功能,然而reactRouter是没有提供路由守卫的api的,只能由我们自己实现。我会先实现路由守卫的基本功能,然后逐步完善它来为reactRouter增添更多功能。我想结合自己对代码的迭代过程来对代码做介绍。
阶段一:实现基本功能
阶段二:多重权限(角色)
阶段三:按需加载路由模块
阶段四:优化路由配置信息的书写格式并实现路由别名功能
如果您时间不多或对我的迭代过程并不感兴趣的话,可以直接从这个地址clone项目源码:https://gitee/yangguang110/react-navigation-guards
这里有项目最新的代码。
或者访问项目主页
项目目录
src
├── router
│ ├── index.ts #入口文件
│ ├── route.config.ts #路由配置
│ ├── Guards.tsx #路由守卫组件
│ └── NotFound.tsx #404页面
├── view
│ ├── console
│ │ └── index.tsx
│ ├── login
│ │ └── index.tsx
│ ├── main
│ │ └── index.tsx
│ ├── news
│ │ └── index.tsx
│ └── user-manage
│ └── index.tsx
└── utils
└── index.tsx
阶段一
这个阶段我想做到以下几点:
- 根据路由配置动态生成嵌套的路由
- 对路由增加访问权限,个别页面只能允许已经登陆的用户访问。权限不足时跳转到登录页面。
- 实现404页面
结合个例子说明。比如,我现在想给一个后台管理系统实现路由,这个后台管理系统有5个页面,分别是控制台(console)、登录页(login)、新闻(news)、用户管理(userManage)、main(控制台主页),其中news、userManage以及main页面都是console的子页面(嵌在console页面内)。除了login之外的四个页面都需要登录后才允许访问。
因此,逻辑是这样的:
如果用户访问不存在的页面则跳转到404。
如果用户未登录,那么访问login页面可以正常访问,而访问其他四个页面会跳转到登录页。
如果用户已经登陆,那么访问login页面会跳转到控制台主页,否则跳转到用户所访问的页面。
下面开始编写代码,因为我打算根据路由配置信息来动态创建路由,所以先编写配置文件。
// src/router/route.config.ts
import Main from "@/view/main"
import Login from "@/view/login"
import News from "@/view/news"
import Console from "@/view/console"
import UserManage from "@/view/user-manage"
export interface RouteModel {
path: string,
component: object,
auth: boolean,
childRoutes?: RouteModel[]
}
/*
这里只需配置好这些路由的相互关系即可
比如login和console是同级(兄弟),而news是console的子路由(父子)
*/
export const routeConfig: RouteModel[] = [
{
path: "/login",
component: Login,
auth: false // false表示不需要登录即可访问
},
{
path: "/console",
component: Console,
auth: true,
childRoutes: [
{
path: "/console/main",
component: Main,
auth: true
},
{
path: "/console/news",
component: News,
auth: true
},
{
path: "/console/userManage",
component: UserManage,
auth: true
}
]
}
]
然后是路由守卫组件,贴源码之前说一下思路。
首先,当我们使用react-router-dom提供的Switch组件将自定义组件包裹起来之后,自定义组件的props中会被注入一些与路径有关的信息,这部分数据的原型如下:
interface RouteProps {
location?: H.Location;
component?: React.ComponentType<RouteComponentProps<any>> | React.ComponentType<any>;
render?: (props: RouteComponentProps<any>) => React.ReactNode;
children?: ((props: RouteChildrenProps<any>) => React.ReactNode) | React.ReactNode;
path?: string | string[];
exact?: boolean;
sensitive?: boolean;
strict?: boolean;
}
其中props.location.pathname
表示当前用户访问的目标路径,在路由守卫中会根据这个来判断应该渲染哪一个组件。
其次,读者需要知道reactRouter是如何实现嵌套路由的,这个可以参考官方示例。以及如何给子路由传值。
最后,必须明确的是,如果我们的路由配置信息中有嵌套路由,那么路由守卫就不可能是一个,每一层路由都会对应一个路由守卫,这些路由守卫之间唯一的区别就是他们需要渲染的路由列表不同。管理第一层路由的守卫需要判断何时该渲染login和console,管理第二层的路由的守卫则判断何时渲染news、userManage和main。
举个现实例子:如果我们访问/console/news
,那么第一层的路由守卫是无法去渲染News组件的,因为它拿不到相应的配置信息,有关/console/news
这个路径的配置是在第二层的路由守卫手里的,但是第一层的路由守卫却有/console
这个路径的信息,于是它只需要把Console组件渲染出来即可。因为News、Main和UserManage都是Console的子路由,所以我们把第二层的路由守卫设置在Console组件内,当Console组件被渲染出来之后,其上的第二层路由路由守卫继续判断/console/news
这个路径,发现这个路径正好是自己管理的,于是将对应的News组件渲染在页面上。
源码如下:
// src/router/Guards.tsx
import React, {
Component } from 'react';
import {
RouteProps } from "react-router"
import {
Route, Redirect } from "react-router-dom"
import NotFound from "./NotFound"
import {
RouteModel } from "./route.config"
import {
permission } from "@/store/mobx"
export interface NavigationGuardsProps extends RouteProps {
routeConfig: RouteModel[]
}
class NavigationGuards extends Component<NavigationGuardsProps, any> {
/**
* 判断一个路径是否是另一个路径的子路径
* @param pathConfig 配置文件中的路径
* @param pathTarget 用户请求的路径
*/
static switchRoute(pathConfig:string,pathTarget:string){
if(pathConfig===pathTarget) return true;
const reg=new RegExp(`(^${
pathConfig})(?=/)`)
return reg.test(pathTarget)
}
render() {
const {
location, routeConfig } = this.props
const targetPath: string | undefined = location && location.pathname
const targetRoute: RouteModel | undefined = routeConfig.find((item) =>
targetPath&&NavigationGuards.switchRoute(item.path,targetPath))
const isLogin = permission.isLogin
if (!targetRoute) {
return <NotFound></NotFound>
}
if (isLogin) {
return <LoginHandler targetRoute={
targetRoute}></LoginHandler>
} else {
return <NotLoginHandler targetRoute={
targetRoute}></NotLoginHandler>
}
}
}
//已经登陆的状态下,处理路由
function LoginHandler(props): any {
const {
targetRoute } = props
const {
path } = targetRoute
if (path ===
本文标签: 路由reactRouter
版权声明:本文标题:reactRouter路由守卫与最佳实践 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/xitong/1729176522a1188788.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论