react + antd 实现后台管理系统
项目效果图
项目完整代码地址
https://gitee.com/lyh1999/react-back-management
项目完整代码地址
react依赖安装 最好采用yarn 安装
react-router 安装依赖
配置路由
history模式 /
// 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模式 #
// 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路由文件
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
import React from 'react'
// 引入子路由出口
import {Outlet} from 'react-router-dom'const Main = () => {return (<div><h1>main</h1><Outlet/></div>)
}export default Main
创建子路由home组件
import React from "react";import './home.css'
const Home = () => {return (<div><h1>Home</h1></div>);
}export default Home;
App.js挂载路由router RouterProvider
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;
导入完整路由组件
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);
改为懒加载
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
完整路由搭建
代码
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
npm install antd
复制官网的Layout 代码到main.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" }}><Sidercollapsiblecollapsed={collapsed}onCollapse={(value) => setCollapsed(value)}><div className="demo-logo-vertical" /><Menutheme="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><divstyle={{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组件抽取出来
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 (<Sidercollapsiblecollapsed={collapsed}onCollapse={(value) => setCollapsed(value)}><h3 style={{ margin: 16, color: "white" }}>通用后台管理系统</h3><Menutheme="dark"defaultSelectedKeys={["1"]}mode="inline"items={items}/></Sider>);
};export default CommonAside;
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><divstyle={{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组件实现
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'}]}]
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 (<Sidercollapsiblecollapsed={collapsed}onCollapse={(value) => setCollapsed(value)}><h3 style={{ margin: 16, color: "white" }}>通用后台管理系统</h3><Menutheme="dark"defaultSelectedKeys={["1"]}mode="inline"items={menuItems}/></Sider>);
};export default CommonAside;