创建项目
安装依赖包npm install sass sass-loader react-router-dom ant
清空无用文件
新建项目工程文件夹
在styles/reset.scss重置样式并在index.scss中引入
@import './assets/styles/reset.scss'
建页面
路由基本配置
import React from 'react'
import { HashRouter, Route, Routes } from 'react-router-dom'
//登录界面
import Login from "./views/login/Login"
export default function App() {
return (
<div>
<HashRouter>
<Routes>
<Route path='/login' element={<Login/>}></Route>
</Routes>
</HashRouter>
</div>
)
}
配置路径别名@
安装:npm install -D @craco/craco
在项目根目录中创建 craco 的配置文件:craco.config.js,并添加如下代码:
const path = require('path')
module.exports = {
// webpack 配置
webpack: {
// 配置别名
alias: {
// 约定:使用 @ 表示 src 文件所在路径
'@': path.resolve(__dirname, 'src'),
},
},
}
在项目根目录中新建 jsconfig.json,并添加如下代码:
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
}
}
}
package.json 修改启动命令
"scripts": {
"start": "craco start",
"build": "craco build",
"test": "craco test",
"eject": "react-scripts eject"
},
路由懒加载和重定向
import React, { lazy, Suspense } from 'react'
import { HashRouter, Navigate, Route, Routes } from 'react-router-dom'
//登录界面
import Login from "@/views/login/Login"
//框架
// 路由懒加载,需要配合suspense使用,否则可能会报错
const Layout = lazy(() => import('@/views/layout/Layout'))
export default function App() {
return (
<div>
<HashRouter>
<Routes>
{/* 重定向 */}
<Route path='/' element={<Navigate to='/layout'></Navigate>}></Route>
<Route path='/login' element={<Login />}></Route>
<Route path='/layout' element={
<Suspense fallback={<div>Loading...</div>}>
<Layout />
</Suspense>
}></Route>
</Routes>
</HashRouter>
</div>
)
}
二级路由
{/* 一级路由 */}
<Route path='/layout' element={
<Suspense fallback={<div>Loading...</div>}>
<Layout />
</Suspense>
}>
{/* 二级路由 */}
<Route path='order' element={
<Suspense fallback={<div>Loading...</div>}>
<OrderManage />
</Suspense>
}>
</Route>
</Route>
二级路由出口
//Layout.jsx
import React from 'react'
import { Outlet } from 'react-router-dom'
export default function Layout() {
return (
<div>
<h1>框架</h1>
{/* 二级路由出口 */}
<Outlet/>
</div>
)
}
在router/index.jsx中路由表
import { lazy } from 'react'
//登录
const Login = lazy(() => import('@/views/login/Login'))
// 框架
const Layout = lazy(() => import('@/views/layout/Layout'))
//数据中心
const DataCenter = lazy(() => import('@/views/dataCenter/DataCenter'))
//客服中心
const OrderManage = lazy(() => import('@/views/callCenter/OrderManage'))
// 审核中心
const StoreAudit = lazy(() => import('@/views/auditCenter/StoreAudit'))
const IdentityAudit = lazy(() => import('@/views/auditCenter/IdentityAudit'))
//运营中心
const SubjectManage = lazy(() => import('@/views/operationCenter/SubjectManage'))
const ProjectManage = lazy(() => import('@/views/operationCenter/ProjectManage'))
//管理中心
const CompanyManage = lazy(() => import('@/views/manageCenter/CompanyManage'))
const DepartmentManage = lazy(() => import('@/views/manageCenter/DepartmentManage'))
//路由表
export default [
//重定向
{
path:'/',
redirect:'/data'
},
// 登录
{
path:'/login',
element:<Login />
},
// 数据中心
{
path:'/data',
element:<Layout/>,
children:[
{
path:'',
element:<DataCenter/>
}
]
},
//客服中心
{
path:'/call',
element:<Layout/>,
children:[
{
path:'order',
element:<OrderManage/>
}
]
},
//审核中心
{
path:'/audit',
element:<Layout/>,
children:[
{
path:'store',
element:<StoreAudit/>
},
{
path:'identity',
element:<IdentityAudit/>
}
]
},
// 运营中心
{
path:'/operation',
element:<Layout/>,
children:[
{
path:'subject',
element:<SubjectManage/>
},
{
path:'project',
element:<ProjectManage/>
}
]
},
// 管理中心
{
path:'/manage',
element:<Layout/>,
children:[
{
path:'company',
element:<CompanyManage/>
},
{
path:'department',
element:<DepartmentManage/>
}
]
}
]
工具函数中渲染动态路由函数
//utils/getRoute.jsx
import { Suspense } from "react"
import { Navigate, Route } from "react-router-dom"
export const getRoute = (routes) => {
return routes.map(item => {
return <Route path={item.path} key={item.path} element={item.redirect && !item.children ? <Navigate to={item.redirect} /> : <Suspense fallback={<div>Loading...</div>}>
{item.element}
</Suspense>}>
{
item.redirect && item.children ? <Route path={item.path} element={<Navigate to={item.redirect} />} ></Route> : ""
}
{
item.children && item.children.length ? getRoute(item.children) : ""
}
</Route>
})
}
App.jsx中
import React from 'react'
import { HashRouter, Routes } from 'react-router-dom'
//引入路由表
import router from './router'
//导入工具函数 渲染路由
import { getRoute } from './utils/getRoute'
export default function App() {
return (
<div>
<HashRouter>
<Routes>
{
getRoute(router)
}
</Routes>
</HashRouter>
</div>
)
}
安装ant design:npm install antd --save
Layout.jsx文件中布局
import React from 'react'
import { Outlet } from 'react-router-dom'
import "./Layout.scss"
import "./components/LeftMenu"
import LeftMenu from './components/LeftMenu'
export default function Layout() {
return (
<div className='layout-wrap'>
<div className='left-menu'>
<LeftMenu/>
</div>
<div className='right-cont'>
<div className='right-top'>2</div>
<div className='right-main'>
{/* 二级路由出口 */}
<Outlet />
</div>
</div>
</div>
)
}
//Layout.scss
.layout-wrap{
display: flex;
height: 100%;
.left-menu{
background-color: skyblue;
// width: 200px;
}
.right-cont{
flex: 1;
display: flex;
flex-direction: column;
.right-top{
height: 50px;
background-color: pink;
}
.right-main{
flex: 1;
padding: 20px;
}
}
}
左边菜单栏完成LeftMenu.jsx中
import React, { useState } from 'react'
import { MailOutlined, SettingOutlined, AppstoreOutlined } from '@ant-design/icons';
import { Menu } from 'antd';
//导出路由跳转hooks函数
import { useNavigate } from 'react-router-dom';
function getItem(label, key, icon, children, type) {
return {
key,
icon,
children,
label,
type,
};
}
const items = [
getItem('数据中心', '/data', <SettingOutlined />),
getItem('客服中心', '2', <MailOutlined />, [
getItem('订单管理', '/call/order')
]),
getItem('审核中心', '3', <AppstoreOutlined />, [
getItem('商户审核', '/audit/store'),
getItem('身份审核', '/audit/identity')
]),
getItem('运营中心', '4', <SettingOutlined />, [
getItem('专题管理', '/operation/subject'),
getItem('项目管理', '/operation/project')
]),
getItem('管理中心', '5', <SettingOutlined />, [
getItem('公司管理', '/manage/company'),
getItem('部门管理', '/manage/department')
]),
];
const rootSubmenuKeys = ['2', '3', '4', '5'];
export default function LeftMenu() {
//展开的subMenu
const [openKeys, setOpenKeys] = useState(['1']);
//点击subMenu的回调函数
const onOpenChange = (keys) => {
const latestOpenKey = keys.find((key) => openKeys.indexOf(key) === -1);
if (rootSubmenuKeys.indexOf(latestOpenKey) === -1) {
setOpenKeys(keys);
} else {
setOpenKeys(latestOpenKey ? [latestOpenKey] : []);
}
};
//路由跳转的函数
const navigate = useNavigate()
//点击每一项
const onClick = (e) => {
console.log('click ', e);
navigate(e.key)
};
return (
<Menu
onClick={onClick}
style={{
width: 256,
background: 'skyblue'
}}
openKeys={openKeys}
onOpenChange={onOpenChange}
mode="inline"
items={items}
/>
)
}