极客园
- 1、项目搭建
- 使用gitee管理项目
- 2、登录模块
-
- [2-1 基本结构搭建](#2-1 基本结构搭建)
- [2-2 表单校验实现](#2-2 表单校验实现)
- [2-3 获取登录表单数据](#2-3 获取登录表单数据)
- [2-4 封装request工具模块](#2-4 封装request工具模块)
- [2-5 使用Redux管理token](#2-5 使用Redux管理token)
- [2-6 实现登录逻辑](#2-6 实现登录逻辑)
- [2-7 token持久化](#2-7 token持久化)
- [2-8 请求拦截器注入token](#2-8 请求拦截器注入token)
- [2-9 路由鉴权实现](#2-9 路由鉴权实现)
1、项目搭建
1-1 创建项目
基于CRA
CRA是一个底层基于webpack快速创建React项目的脚手架工具
bash
# 使用npx创建项目
npx create-react-app react-jike
# 进入到项
cd react-jike
# 启动项目
npm start
基于vite
bash
npm create vite@latest react-jike -- --template react
# 进入到项
cd react-jike
# 安装依赖
nmp install
# 启动项目
npm run dev

1-2 调整项目目录结构
bash
-src
-apis 项目接口函数
-assets 项目资源文件,比如,图片等
-components 通用组件
-pages 页面组件
-router 路由
-store 集中状态管理
-utils 工具,比如,token、axios 的封装等
-App.js 根组件
-index.css 全局样式
-index.js 项目入口

src/main.jsx
jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import './index.scss'
import './App.js'
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App/>
</React.StrictMode>
)
src/App.jsx
jsx
const App = () => {
return <div>this is app</div>
}
export default App
1-3 使用scss预处理器
SASS是一种预编译的 CSS,支持一些比较高级的语法,可以提高编写样式的效率,CRA接入scss非常简单只需要我们装一个sass工具

实现步骤
- 安装解析 sass 的包:
npm i sass -D - 创建全局样式文件:
index.scss
css
body {
margin: 0;
div {
color: blue;
}
}
1-4 组件库antd使用
极客园项目是一个传统的PC管理后台,有现成的组件库可以使用,帮助我们提升开发效率,其中使用最广的就是antD
Ant Design of React - Ant Design

实现步骤
- 安装 antd 组件库:
npm i antd - 导入 Button 组件
- 在 Login 页面渲染 Button 组件进行测试
测试Button
pages/Login/index.jsx
jsx
import { Button } from 'antd'
const Login = () => {
return <div>this is login<Button type='primary'>test</Button></div>
}
export default Login
1-5 配置基础路由
单页应用需要对应的路由支持,我们使用
react-router-dom最新版本
实现步骤
- 安装路由包
npm i react-router-dom - 准备
Layout和Login俩个基础组件 - 配置路由
代码实现
pages/Layout/index.jsx
jsx
const Layout = () => {
return <div>this is layout</div>
}
export default Layout
pages/Login/index.jsx
jsx
const Login = () => {
return <div>this is login</div>
}
export default Login
router/index.jsx
jsx
import { createBrowserRouter } from 'react-router-dom'
import Login from '../pages/Login'
import Layout from '../pages/Layout'
const router = createBrowserRouter([
{
path: '/',
element: <Layout />,
},
{
path: '/login',
element: <Login />,
},
])
export default router
main.jsx
jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import './index.scss'
import router from './router'
import { RouterProvider } from 'react-router-dom'
ReactDOM.createRoot(document.getElementById('root')).render(
<RouterProvider router={router} />
)
1-6 配置别名路径
项目背景:在业务开发过程中文件夹的嵌套层级可能会比较深,通过传统的路径选择会比较麻烦也容易出错,设置路径别名可以简化这个过程
路径编译配置
CRA创建的项目
- 安装
craco工具包 - 增加
craco.config.js配置文件 - 修改
scripts 命令 - 测试是否生效
bash
npm i @craco/craco -D
javascript
const path = require('path')
module.exports = {
// webpack 配置
webpack: {
// 配置别名
alias: {
// 约定:使用 @ 表示 src 文件所在路径
'@': path.resolve(__dirname, 'src')
}
}
}
json
"scripts": {
"start": "craco start",
"build": "craco build",
"test": "craco test",
"eject": "react-scripts eject"
}
javascript
import { createBrowserRouter } from 'react-router-dom'
import Login from '@/pages/Login'
import Layout from '@/pages/Layout'
const router = createBrowserRouter([
{
path: '/',
element: <Layout />,
},
{
path: '/login',
element: <Login />,
},
])
export default router
vite创建的项目
Vite本身内置了路径别名(别名解析) 的配置能力,无需额外安装类似 craco 的插件,直接在vite.config.js/ts中通过 resolve.alias配置即可实现路径解析,这是 Vite 原生支持的核心特性,比 CRA + craco 更简洁。
vite.config.js
jsx
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import * as path from 'path';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
resolve: {
// 路径别名配置
alias: {
// 配置 @ 指向 src 目录
'@': path.resolve(__dirname, 'src'),
},
},
})
VsCode提示配置
vite和CRA创建都需要
实现步骤
- 在项目根目录创建
jsconfig.json配置文件 - 在配置文件中添加以下配置
代码实现
json
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
}
}
}
说明:VSCode会自动读取jsconfig.json 中的配置,让vscode知道@就是src目录
使用gitee管理项目
实现步骤
- 在gitee上初始化一个空项目仓库
- 把远程仓库和本地仓库关联
- 提交代码到远程仓库


提交代码-01项目搭建

2、登录模块
2-1 基本结构搭建
实现步骤
- 在
Login/index.js中创建登录页面基本结构 - 在 Login 目录中创建 index.scss 文件,指定组件样式
- 将
logo.png和login.png拷贝到 assets 目录中
代码实现
pages/Login/index.js
jsx
import './index.scss'
import { Card, Form, Input, Button } from 'antd'
import logo from '@/assets/logo.png'
const Login = () => {
return (
<div className="login">
<Card className="login-container">
<img className="login-logo" src={logo} alt="" />
{/* 登录表单 */}
<Form>
<Form.Item>
<Input size="large" placeholder="请输入手机号" />
</Form.Item>
<Form.Item>
<Input size="large" placeholder="请输入验证码" />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" size="large" block>
登录
</Button>
</Form.Item>
</Form>
</Card>
</div>
)
}
export default Login
pages/Login/index.scss
css
.login {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
background: center/cover url('@/assets/login.png');
.login-logo {
width: 200px;
height: 60px;
display: block;
margin: 0 auto 20px;
}
.login-container {
width: 440px;
height: 360px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
box-shadow: 0 0 50px rgb(0 0 0 / 10%);
}
.login-checkbox-label {
color: #1890ff;
}
}

2-2 表单校验实现
表单校验可以在提交登录之前校验用户的输入是否符合预期,如果不符合就阻止提交, 显示错误信息
1-参考官网实现基础Demo FormItem绑定name/FormItem绑定rules
2-按照业务定制化修改 增加失焦时校验/手机号为有效格式
实现步骤
- 为 Form 组件添加
validateTrigger属性,指定校验触发时机的集合 - 为 Form.Item 组件添加 name 属性
- 为 Form.Item 组件添加
rules属性,用来添加表单校验规则对象

validateTrigger="onBlur"实现失焦时校验
代码实现
page/Login/index.js

2-3 获取登录表单数据
当用户输入了正确的表单内容,点击确认按钮时需要收集到用户当前输入的内容,用来提交接口请求
解决方案:给Form组件绑定onFinish回调函数,通过回调函数的参数获取用户输入的内容
实现步骤
- 为 Form 组件添加
onFinish属性,该事件会在点击登录按钮时触发 - 创建 onFinish 函数,通过函数参数 values 拿到表单值
- Form 组件添加
initialValues属性,来初始化表单值
代码实现
pages/Login/index.js

测试

提交代码-02登录表单校验和数据收集

2-4 封装request工具模块
业务背景: 前端需要和后端拉取接口数据,axios是使用最广的工具插件,针对于项目中的使用,我们需要做一些简单的封装
实现步骤
- 安装 axios 到项目
- 创建 utils/request.js 文件
- 创建 axios 实例,配置
baseURL,请求拦截器,响应拦截器 - 在 utils/index.js 中,统一导出request
bash
npm i axios
代码实现
utils/request.jsx
jsx
// axios的封装处理
const { default: axios } = require("axios");
// 1.根域名配置
// 2.超时时间
// 3.请求拦截器 / 响应拦截器
const request = axios.create({
baseURL: 'http://geek.itheima.net/v1_0',
timeout: 5000
})
// 添加请求拦截器
// 在请求发送之前 做拦截 插入一些自定义的配置 [参数的处理]
request.interceptors.request.use((config) => {
return config
}, (error) => {
return Promise.reject(error)
})
// 添加响应拦截器
// 在响应返回客户端之前 做拦截 重点处理返回的数据
request.interceptors.response.use((response) => {
// 2xx 范围内的状态码都会触发该函数。
// 对响应数据做点什么
return response.data
}, (error) => {
// 超出 2xx 范围的状态码都会触发该函数。
// 对响应错误做点什么
return Promise.reject(error)
})
export { request }
utils/index.jsx
bash
// 统一中转工具模块函数
import { request } from "./request"
export {
request
}
提交-03登录-axios封装处理

2-5 使用Redux管理token
安装Redux相关工具包
bash
npm i react-redux @reduxjs/toolkit

配置Redux
代码实现
user.jsx
jsx
// 用户相关的状态管理
import { createSlice } from "@reduxjs/toolkit"
const useStore = createSlice({
name: 'user',
// 数据状态
initialState: {
token: ''
},
// 同步修改方法
reducers: {
setToken(state, action) {
state.token = action.payload
}
}
})
// 解构出actionCreater
const { setToken } = useStore.actions
// 获取reducer函数
const userReducer = useStore.reducer
export { setToken }
export default userReducer
index.jsx
jsx
// 组合redux子模块 导出store实例
import { configureStore } from "@reduxjs/toolkit"
import userReducer from "./modules/user"
const store = configureStore({
reducer: {
user: userReducer
}
})
export default store
main.jsx
jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import './index.scss'
import router from './router'
import { RouterProvider } from 'react-router-dom'
import { Provider } from 'react-redux'
import store from './store'
ReactDOM.createRoot(document.getElementById('root')).render(
<Provider store={store}>
<RouterProvider router={router} />
</Provider>
)
在接口文章找到注册登录的post地址复制,编写异步方法

在组件中触发异步方法

测试,正确的11位手机号,注意验证码是246810,输入别的会发生错误

2-6 实现登录逻辑
业务逻辑:
- 跳转到首页
- 提示用户登录成功
使用async/await
async:给函数 "打标签",标记这是异步函数
await:"等待" Promise 完成,提取最终结果
代码实现

提交-04使用redux维护数据

2-7 token持久化
业务背景: Token数据具有一定的时效时间,通常在几个小时,有效时间内无需重新获取,而基于Redux的存储方式又是基于内存的,刷新就会丢失,为了保持持久化,我们需要单独做处理
原因:Redux是基于浏览器内存的存储方式,刷新时状态会恢复初始值

实现持久化逻辑
代码实现

测试,刷新浏览器,通过Redux调试工具查看token数据

提交-05token持久化

封装token的存取方法
对于Token的各类操作在项目多个模块中都有用到,为了共享复用可以封装成工具函数
代码实现
utils/token.jsx

utils/index.jsx

修改store/modules/user.jsx

提交-06封装token工具和方法

2-8 请求拦截器注入token
业务背景: Token作为用户的数据标识,在接口层面起到了接口权限控制的作用,也就是说后端有很多接口都需要通过查看当前请求头信息中是否含有token数据,来决定是否正常返回数据(接口权限)


拼接方式:config.headers.Authorization = `Bearer ${token}`
config.headers.Authorization:axios 提供的 "请求头字段"
`Bearer ${token}`:后端要求的 "Token 格式",两者之间必须加一个空格
注意:这个拼接方式一定要写对,不然就会请求失败
代码实现

测试

提交-07token的注入

2-9 路由鉴权实现
业务背景:封装
AuthRoute路由鉴权高阶组件,实现未登录拦截,并跳转到登录页面(路由权限)实现思路:判断本地是否有token,如果有,就返回子组件,否则就重定向到登录Login
根据Token的有无控制当前路由是否可以跳转就是路由的权限控制

高阶组件:接收组件作为参数,返回新组件的函数(不是组件,是 "造组件的函数")。
实现步骤
- 在 components 目录中,创建
AuthRoute/index.jsx文件 - 登录时,直接渲染相应页面组件
- 未登录时,重定向到登录页面
- 将需要鉴权的页面路由配置,替换为 AuthRoute 组件渲染
代码实现
components/AuthRoute.jsx

Router/index.jsx

提交08-token控制路由权限


