# 第二篇
# 路由和权限搭建
# 继续上一篇:✋手摸手系列(一/1): vite react typescript reactHook mobx(非脚手架)(从0开始)(包含路由权限控制) (opens new window)
# 后台系列目录
# ✋手摸手系列(一/1): vite react typescript reactHook mobx(非脚手架)(从0开始)(包含路由权限控制) (opens new window)
# ✋手摸手系列(一/2): vite react typescript reactHook mobx(非脚手架)(从0开始):路由和权限搭建 (opens new window)
# 参考资料 umi路由设计https://umijs.org/zh-CN/docs/routing#页面跳转
# 项目地址 https://github.com/wowhoonet/vite-react-mobx-admin
# 路由搭建
# 安装 react-route react-route-dom 依赖
yarn add react-router react-router-dom
yarn add @types/react-router @types/react-router-dom -D
1
2
2
# 在根目录创建 route>index.ts, 代码如下:
import React from "react";
/**
* 路由文件
*/
export interface IRoute {
path: string;
exact?: boolean;
component?: React.ComponentType<any>;
routes?: IRoute[];
wrappers?: React.ComponentType<any>[];
title?: string;
redirect?: string;
hide?: boolean;
icon?: any;
}
export const routes: IRoute [] = [
{
path: '/home',
exact: true,
title: 'home页面',
component: React.lazy(() => import("@/view/Home")),
}
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 新增入口文件 view->App->index.tsx 代码如下:
import { IRoute, routes } from '@/route';
import React, { Suspense, useMemo } from 'react';
import { Redirect, Route, Switch } from 'react-router-dom';
import styles from './index.module.less';
export default function App (): React.ReactElement {
const getChildrenComponent = (
route: IRoute,
key: number,
pPath: string = ""
) => {
const path = pPath + route.path;
return route.redirect ? (
<Redirect key={key} to={route.redirect} from={route.path}></Redirect>
) : (
(route.component || route.routes?.length > 0) && (
<Route key={key} path={path} exact={route.exact}>
{route.wrappers?.length > 0
? route.wrappers.reduceRight(
(element: any, wrapper: any) =>
React.createElement(wrapper, {}, element),
React.createElement(
route.component || React.Fragment,
{},
<Switch>
{route?.routes?.map((croute, rindex) =>
getChildrenComponent(croute, rindex, path)
)}
</Switch>
)
)
: React.createElement(
route.component || React.Fragment,
{},
<Switch>
{route?.routes?.map((croute, rindex) =>
getChildrenComponent(croute, rindex, path)
)}
</Switch>
)}
</Route>
)
);
};
const Routes = useMemo(() => {
const _Routes = routes.map((route, rindex) =>
getChildrenComponent(route, rindex)
);
console.log(_Routes, "_Routes");
return _Routes;
}, []);
return <Suspense fallback={<div>加载中</div>}>
<HashRouter basename="/">
<Switch>{Routes}</Switch>
</HashRouter>
</Suspense>
}
1
2
3
4
5
6
7
8
9
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
2
3
4
5
6
7
8
9
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
这里需要注意的是我们的 routes 结构是个嵌套结构,所以我们需要抽出方法来实现递归,这里有个wrappers大家可以猜一下干甚用的,下面马上就要讲到了
# 这时候 yarn dev 跑一下, 然后访问http://localhost:3000/#/home 应该就可以看到效果了
# 权限控制
# wrapper
译为:包装器
概念来源于 umi 的路由设计,小看了一下源码,然后加入到咱们项目中来
# 开整 wrapper 设计
- 新建 wrappers->auth.tsx
import React from 'react';
import { Redirect } from 'react-router';
import styles from './index.module.less';
export default function Auth (props: {
children: React.ReactElement
}): React.ReactElement {
const isLogin = false; // 后续换成自己的 token 校验
const {children, ...cprops} = props;
if(isLogin) {
return children
}
return <Redirect to="/login"></Redirect>;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
大家看到这里应该知道我的用意了吧,意思是如果我登录了我就渲染我的 children,如果没有登录就重定向到 login;结合一下 route 里面的wraper代码
// xxx
route.wrappers.reduceRight(
(element: any, wrapper: any) =>
React.createElement(wrapper, {}, element),
React.createElement(
route.component || React.Fragment,
{},
<Switch>
{route?.routes?.map((croute, rindex) =>
getChildrenComponent(croute, rindex, path)
)}
</Switch>
)
)
// xxx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
用 wraper 把要渲染的路由包裹起来,就起到了高阶组件的用意了,也就是拦截器的作用
现在完善一下 view->Login 路由组件和 route->index.ts 的路由内容
# Run!run 跑起来
在地址栏输入 http://localhost:3000/#/home 会自动重定向到 login
# 总结
- 引入 react-router 系列包
- 通过递归方式生成
组件,原理是通过 React.createElement生成包裹组件 - 通过wrapper 的方式进行路由拦截