文章目录
项目效果图
项目完整代码地址
https://gitee.com/lyh1999/react-back-management
项目完整代码地址
react依赖安装 最好采用yarn 安装
react-router 安装依赖
配置路由
history模式 /
react
// src/router/index.jsx
import { createBrowserRouter } from "react-router-dom";
import Home from "../views/Home";
import Login from "../views/Login";
const router = createBrowserRouter([
{
path:'/',
element: <Home />,
},
{
path:'/login',
element: <Login />,
}
])
export default router
hash模式 #
react
// src/router/index.jsx
import { createHashRouter } from "react-router-dom";
import Home from "../views/Home";
import Login from "../views/Login";
const router = createHashRouter([
{
path: "/",
element: <Home />,
},
{
path: "/login",
element: <Login />,
},
]);
export default router;
basename 设置子路由的前缀
创建router路由文件
js
import { createBrowserRouter } from "react-router-dom";
import Main from "../pages/main";
import Home from "../pages/home";
const routes = [
{
path: "/",
Component: Main,
children: [{
path: "/home",
Component: Home,
}],
},
];
export default createBrowserRouter(routes);
创建main.js main组件 这里可以挂载子路由出口Outlet
js
import React from 'react'
// 引入子路由出口
import {Outlet} from 'react-router-dom'
const Main = () => {
return (
<div>
<h1>main</h1>
<Outlet/>
</div>
)
}
export default Main
创建子路由home组件
js
import React from "react";
import './home.css'
const Home = () => {
return (
<div>
<h1>Home</h1>
</div>
);
}
export default Home;
App.js挂载路由router RouterProvider
js
import "./App.css";
import { RouterProvider } from "react-router-dom";
import router from "./router/index";
function App() {
return (
<div className="App">
<RouterProvider router={router} />
</div>
);
}
export default App;
导入完整路由组件
js
import { createBrowserRouter } from "react-router-dom";
import Main from "../pages/main";
import Home from "../pages/home";
import Mall from "../pages/mall";
import User from "../pages/user";
const routes = [
{
path: "/",
Component: Main,
children: [{
path: "/home",
Component: Home,
},{
path: "/user",
Component: User,
},{
path: "/mall",
Component: Mall,
}],
},
];
export default createBrowserRouter(routes);
改为懒加载
js
import { createBrowserRouter, lazy, Suspense } from "react-router-dom";
import Main from "../pages/main"; // 主布局组件可以提前加载
// 使用 React.lazy 动态导入组件
const Home = lazy(() => import("../pages/home"));
const Mall = lazy(() => import("../pages/mall"));
const User = lazy(() => import("../pages/user"));
const routes = [
{
path: "/",
element: <Main />,
children: [
{
path: "home", // 注意:子路由路径不需要以斜杠开头
element: (
<Suspense fallback={<div>Loading...</div>}>
<Home />
</Suspense>
),
},
{
path: "user",
element: (
<Suspense fallback={<div>Loading...</div>}>
<User />
</Suspense>
),
},
{
path: "mall",
element: (
<Suspense fallback={<div>Loading...</div>}>
<Mall />
</Suspense>
),
},
],
},
];
export default createBrowserRouter(routes);
添加完整路由组件 mall user pageOne pageTwo
完整路由搭建
代码
js
import { createBrowserRouter, Navigate } from "react-router-dom";
import { Suspense, lazy } from "react";
import Main from "../pages/main"; // 主布局组件可以提前加载
// 使用 React.lazy 动态导入组件
const Home = lazy(() => import("../pages/home"));
const Mall = lazy(() => import("../pages/mall"));
const User = lazy(() => import("../pages/user"));
const PageTwo = lazy(() => import("../pages/other/pageTwo"));
const PageOne = lazy(() => import("../pages/other/pageOne"));
const routes = [
{
path: "/",
element: <Main />,
children: [
// 路由重定向
{
path: "/",
element: <Navigate to={"/home"} replace />,
},
{
path: "home", // 注意:子路由路径不需要以斜杠开头
element: (
<Suspense fallback={<div>Loading...</div>}>
<Home />
</Suspense>
),
},
{
path: "user",
element: (
<Suspense fallback={<div>Loading...</div>}>
<User />
</Suspense>
),
},
{
path: "mall",
element: (
<Suspense fallback={<div>Loading...</div>}>
<Mall />
</Suspense>
),
},
{
path: "other",
children:[{
path: "pageOne",
element: (
<Suspense fallback={<div>Loading...</div>}>
<PageOne />
</Suspense>
)
},{
path: "pageTwo",
element: (
<Suspense fallback={<div>Loading...</div>}>
<PageTwo />
</Suspense>
)
}]
}
],
},
];
export default createBrowserRouter(routes);
Layout 和 Aside组件引入 Antd
shell
npm install antd
复制官网的Layout 代码到main.js
js
import React, { useState } from "react";
// 引入子路由出口
import { Outlet } from "react-router-dom";
import {
DesktopOutlined,
FileOutlined,
PieChartOutlined,
TeamOutlined,
UserOutlined,
} from "@ant-design/icons";
import { Breadcrumb, Layout, Menu, theme } from "antd";
const { Header, Content, Footer, Sider } = Layout;
const items = [
getItem("Option 1", "1", <PieChartOutlined />),
getItem("Option 2", "2", <DesktopOutlined />),
getItem("User", "sub1", <UserOutlined />, [
getItem("Tom", "3"),
getItem("Bill", "4"),
getItem("Alex", "5"),
]),
getItem("Team", "sub2", <TeamOutlined />, [
getItem("Team 1", "6"),
getItem("Team 2", "8"),
]),
getItem("Files", "9", <FileOutlined />),
];
function getItem(label, key, icon, children) {
return {
key,
icon,
children,
label,
};
}
const Main = () => {
const [collapsed, setCollapsed] = useState(false);
const {
token: { colorBgContainer, borderRadiusLG },
} = theme.useToken();
return (
<Layout style={{ minHeight: "100vh" }}>
<Sider
collapsible
collapsed={collapsed}
onCollapse={(value) => setCollapsed(value)}
>
<div className="demo-logo-vertical" />
<Menu
theme="dark"
defaultSelectedKeys={["1"]}
mode="inline"
items={items}
/>
</Sider>
<Layout>
<Header style={{ padding: 0, background: colorBgContainer }} />
<Content style={{ margin: "0 16px" }}>
<Breadcrumb style={{ margin: "16px 0" }}>
<Breadcrumb.Item>User</Breadcrumb.Item>
<Breadcrumb.Item>Bill</Breadcrumb.Item>
</Breadcrumb>
<div
style={{
padding: 24,
minHeight: 360,
background: colorBgContainer,
borderRadius: borderRadiusLG,
}}
>
Bill is a cat.
</div>
</Content>
<Footer style={{ textAlign: "center" }}>
Ant Design ©{new Date().getFullYear()} Created by Ant UED
</Footer>
</Layout>
</Layout>
);
};
export default Main;
组件抽离 将side组件抽取出来
js
import React, { useState } from "react";
import { Layout, Menu } from "antd";
import {
DesktopOutlined,
FileOutlined,
PieChartOutlined,
TeamOutlined,
UserOutlined,
} from "@ant-design/icons";
const { Sider } = Layout;
const items = [
getItem("Option 1", "1", <PieChartOutlined />),
getItem("Option 2", "2", <DesktopOutlined />),
getItem("User", "sub1", <UserOutlined />, [
getItem("Tom", "3"),
getItem("Bill", "4"),
getItem("Alex", "5"),
]),
getItem("Team", "sub2", <TeamOutlined />, [
getItem("Team 1", "6"),
getItem("Team 2", "8"),
]),
getItem("Files", "9", <FileOutlined />),
];
function getItem(label, key, icon, children) {
return {
key,
icon,
children,
label,
};
}
const CommonAside = () => {
const [collapsed, setCollapsed] = useState(false);
return (
<Sider
collapsible
collapsed={collapsed}
onCollapse={(value) => setCollapsed(value)}
>
<h3 style={{ margin: 16, color: "white" }}>通用后台管理系统</h3>
<Menu
theme="dark"
defaultSelectedKeys={["1"]}
mode="inline"
items={items}
/>
</Sider>
);
};
export default CommonAside;
js
import React from "react";
// 引入子路由出口
import { Outlet } from "react-router-dom";
import { Breadcrumb, Layout, theme } from "antd";
import CommonAside from "../components/commonAside";
const { Header, Content, Footer } = Layout;
const Main = () => {
const {
token: { colorBgContainer, borderRadiusLG },
} = theme.useToken();
return (
<Layout style={{ minHeight: "100vh" }}>
<CommonAside />
<Layout>
<Header style={{ padding: 0, background: colorBgContainer }} />
<Content style={{ margin: "0 16px" }}>
<Breadcrumb style={{ margin: "16px 0" }}>
<Breadcrumb.Item>User</Breadcrumb.Item>
<Breadcrumb.Item>Bill</Breadcrumb.Item>
</Breadcrumb>
<div
style={{
padding: 24,
minHeight: 360,
background: colorBgContainer,
borderRadius: borderRadiusLG,
}}
>
Bill is a cat.
</div>
</Content>
<Footer style={{ textAlign: "center" }}>
Ant Design ©{new Date().getFullYear()} Created by Ant UED
</Footer>
</Layout>
</Layout>
);
};
export default Main;
Aside组件实现
js
export default [
{
path: '/home',
name: 'home',
label: '首页',
icon: 'HomeOutlined',
url: '/home/index'
},
{
path: '/mall',
name: 'mall',
label: '商品管理',
icon: 'ShopOutlined',
url: '/mall/index'
},
{
path: '/user',
name: 'user',
label: '用户管理',
icon: 'UserOutlined',
url: '/user/index'
},
{
path: '/other',
label: '其他',
icon: 'SettingOutlined',
children: [
{
path: '/other/pageOne',
name: 'page1',
label: '页面1',
icon: 'SettingOutlined'
},
{
path: '/other/pageTwo',
name: 'page2',
label: '页面2',
icon: 'SettingOutlined'
}
]
}
]
js
import React, { useState } from "react";
import { Layout, Menu } from "antd";
import * as Icon from "@ant-design/icons";
import MenuConfig from "../../config/index";
const { Sider } = Layout;
// 动态获取icon
const iconToElement = (iconName) => React.createElement(Icon[iconName]);
// 处理菜单数据 items项设置必须要有key icon label
const menuItems = MenuConfig.map((item) => {
// 没有子菜单
const child = {
key: item.path,
icon: iconToElement(item.icon),
label: item.label,
};
// 有子菜单
if (item.children) {
child.children = item.children.map((child) => {
return {
key: child.path,
icon: iconToElement(child.icon),
label: child.label,
};
});
}
return child;
});
const CommonAside = () => {
const [collapsed, setCollapsed] = useState(false);
return (
<Sider
collapsible
collapsed={collapsed}
onCollapse={(value) => setCollapsed(value)}
>
<h3 style={{ margin: 16, color: "white" }}>通用后台管理系统</h3>
<Menu
theme="dark"
defaultSelectedKeys={["1"]}
mode="inline"
items={menuItems}
/>
</Sider>
);
};
export default CommonAside;