前情提要-项目搭建和登录模块完成
Layout模块
- 3、Layout模块
-
- [3-1 本结构和样式reset](#3-1 本结构和样式reset)
- [3-2 二级路由配置](#3-2 二级路由配置)
- [3-3 路由菜单点击交互实现](#3-3 路由菜单点击交互实现)
- [3-4 展示个人信息](#3-4 展示个人信息)
- [3-5 退出登录实现](#3-5 退出登录实现)
- [3-6 处理Token失效](#3-6 处理Token失效)
- [3-7 首页Home图表展示](#3-7 首页Home图表展示)
- [3-8 API模块封装](#3-8 API模块封装)
3、Layout模块
3-1 本结构和样式reset
结构创建
pages/Layout/index.jsx
jsx
import { Layout, Menu, Popconfirm } from 'antd'
import {
HomeOutlined,
DiffOutlined,
EditOutlined,
LogoutOutlined,
} from '@ant-design/icons'
import './index.scss'
const { Header, Sider } = Layout
const items = [
{
label: '首页',
key: '1',
icon: <HomeOutlined />,
},
{
label: '文章管理',
key: '2',
icon: <DiffOutlined />,
},
{
label: '创建文章',
key: '3',
icon: <EditOutlined />,
},
]
const GeekLayout = () => {
return (
<Layout>
<Header className="header">
<div className="logo" />
<div className="user-info">
<span className="user-name">柴柴老师</span>
<span className="user-logout">
<Popconfirm title="是否确认退出?" okText="退出" cancelText="取消">
<LogoutOutlined /> 退出
</Popconfirm>
</span>
</div>
</Header>
<Layout>
<Sider width={200} className="site-layout-background">
<Menu
mode="inline"
theme="dark"
defaultSelectedKeys={['1']}
items={items}
style={{ height: '100%', borderRight: 0 }}></Menu>
</Sider>
<Layout className="layout-content" style={{ padding: 20 }}>
内容
</Layout>
</Layout>
</Layout>
)
}
export default GeekLayout
pages/Layout/index.scss
bash
.ant-layout {
height: 100%;
}
.header {
padding: 0;
}
.logo {
width: 200px;
height: 60px;
background: url('@/assets/logo.png') no-repeat center / 160px auto;
}
.layout-content {
overflow-y: auto;
}
.user-info {
position: absolute;
right: 0;
top: 0;
padding-right: 20px;
color: #fff;
.user-name {
margin-right: 20px;
}
.user-logout {
display: inline-block;
cursor: pointer;
}
}
.ant-layout-header {
padding: 0 !important;
}
样式初始化
bash
npm install normalize.css
main.jsx中引入

index.scss
css
html,
body {
margin: 0;
height: 100%;
}
#root {
height: 100%;
}
3-2 二级路由配置
使用步骤
- 在 pages 目录中,分别创建:Home(数据概览)/Article(内容管理)/Publish(发布文章)页面文件夹
- 分别在三个文件夹中创建 index.jsx 并创建基础组件后导出
- 在
router/index.js中配置嵌套子路由,在Layout中配置二级路由出口 - 使用 Link 修改左侧菜单内容,与子路由规则匹配实现路由切换



代码实现
pages/Home/index.jsx
jsx
const Home = () => {
return <div>Home</div>
}
export default Home
pages/Article/index.jsx
jsx
const Article = () => {
return <div>Article</div>
}
export default Article
pages/Publish/index.jsx
jsx
const Publish = () => {
return <div>Publish</div>
}
export default Publish
router/index.jsx
jsx
import { createBrowserRouter } from 'react-router-dom'
import Login from '@/pages/Login'
import Layout from '@/pages/Layout'
import Publish from '@/pages/Publish'
import Article from '@/pages/Article'
import Home from '@/pages/Home'
import { AuthRoute } from '@/components/Auth'
const router = createBrowserRouter([
{
path: '/',
element: (
<AuthRoute>
<Layout />
</AuthRoute>
),
children: [
{
index: true,
element: <Home />,
},
{
path: 'article',
element: <Article />,
},
{
path: 'publish',
element: <Publish />,
},
],
},
{
path: '/login',
element: <Login />,
},
])
export default router
配置二级路由出口

3-3 路由菜单点击交互实现
点击菜单跳转路由
点击左侧菜单可以跳转到对应的目标路由



提交-09点击菜单跳转路由

根据当前路径菜单反向高亮
实现效果:页面在刷新时可以根据当前的路由路径让对应的左侧菜单高亮显示

思路分析
- 获取当前url上的路由路径
- 找到菜单组件负责高亮的属性,绑定当前的路由路径
使用一个钩子函数useLocation,用于在函数组件中获取当前页面的「路由位置信息」(包括 URL 路径、查询参数、hash、状态等),获取当前的key
使用这个属性selectedKeys

提交-10layout-根据路由路径高亮菜单

3-4 展示个人信息
用户的信息通常很有可能在多个组件中都需要共享使用,同样应该放到Redux中维护

实现步骤
- 在Redux的store中编写获取用户信息的相关逻辑
- 在Layout组件中触发action的执行
- 在Layout组件使用使用store中的数据进行用户名的渲染
代码实现
store/userStore.jsx

pages/Layout/index.js

测试get请求是否成功

提交-11layout获取渲染用户信息

3-5 退出登录实现

实现步骤
- 为气泡确认框添加确认回调事件
- 在
store/userStore.js中新增退出登录的action函数,在其中删除token - 在回调事件中,调用userStore中的退出action
- 清除用户信息,返回登录页面
代码实现
store/modules/user.jsx

pages/Layout/index.jsx

调用Popconfirm 组件的事件属性onConfirm,在onConfirm中编写退出登录的函数
提交-12layout退出登录实现

3-6 处理Token失效
业务背景:如果用户一段时间不做任何操作,到时之后应该清除所有过期用户信息跳回到登录
通常在Token失效之后再去请求接口,后端会返回401状态码,前端可以监控这个状态做后续的操作




根据401状态码做操作
utils/request.jsx

提交-13token的失效处理

3-7 首页Home图表展示
bash
// 导入
import * as echarts from 'echarts';
// 1.获取渲染图标的Dom节点
var chartDom = document.getElementById('main');
// 2.图标初始化生成图表实例对象
var myChart = echarts.init(chartDom);
// 3.准备图表参数
var option = {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [
{
data: [120, 200, 150, 80, 70, 110, 130],
type: 'bar'
}
]
};
// 4.使用图表参数完成图表的渲染
option && myChart.setOption(option);
图表基础Demo实现
图表类业务渲染,我们可以通过下面的顺序来实现
- 跑通基础DEMO
- 按照实际业务需求进行修改

安装echarts
bash
npm i echarts
实现基础Demo
ECharts 图表节点必须设置宽高
pages/Home/index.jsx

提交-14echarts图表初始化

组件封装


提交-15echarts组件封装

3-8 API模块封装
把项目中的所有接口按照业务模块以函数的形式统一封装到apis模块中

apis/user.jsx
jsx
// 封装用户相关的所有请求
import { request } from "@/utils"
// 1.登录请求
export function loginAPI(formData) {
// axios规范写法
return request({
url: '/authorizations',
method: 'POST',
data: formData
})
}
// 2.获取用户相关信息
export function getProfilrAPI() {
return request({
url: '/user/profile',
method: 'GET'
})
}
store/modules/user,jsx

提交-16封装apis模块
