前言
后台管理系统是前端永远绕不开的话题,无论技术怎么革新,检验技术最好的标准就是如何做好产品。如今的前端可谓是百花齐放,百家争鸣,甚至学不过来了!吐血~ 本节主要讲述如何使用react、react-router-dom封装侧边栏。
介绍
yarn add react-router-dom
react-router-dom
: 基于react-router
,加入了在浏览器运行环境下的一些功能:
-
Link
组件,会渲染一个a
标签; -
BrowserRouter
组件,使用pushState
和popState
事件构建路由; -
HashRouter
组件,使用window.location.hash
和hashchange
事件构建路由。 -
react-router-native
: 基于react-router
,类似react-router-dom
,加入了react-native
运行环境下的一些功能。
开始
描述:图例就是简单的后台管理系统模板,左侧的导航栏通过路由控制内容区域的显示。页面过于简单,后面会重新替换,见谅!项目的ui是基于antD。
- 新建views文件夹放置页面
- 在views下分模块放置各类页面(首页:home)
import React, { Component } from "react";
// layout组件
import LayoutAside from "./components/aside";
import LayoutHeader from "./components/header";
import ContainerMain from "../../components/containerMain/Index";
// css
import "./layout.scss";
// antD
import { Layout } from "antd";
const { Sider, Header, Content } = Layout;
export default class Index extends Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
return (
<Layout className="layout-wrap">
<Header className="layout-header">
<LayoutHeader />
</Header>
<Layout>
<Sider className="layout-side">
<LayoutAside />
</Sider>
<Content className="layout-main">
<ContainerMain />
</Content>
</Layout>
</Layout>
);
}
}
描述:首页是由登录页面进来的。我们从外部引入三个组件LayoutAside、LayoutHeader、ContainerMain,分别展示侧边栏、头部、内容区。
- LayoutAside
import React, { Component } from "react";
//asideMenu
import AsideMenu from "../../../components/asideMenu/index";
export default class Aside extends Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
return <AsideMenu />;
}
}
- LayoutHeader
import React, { Component, Fragment } from "react";
//css
import "./aside.scss";
export default class Header extends Component {
constructor(prpos) {
super(prpos);
this.state = {};
}
render() {
return (
<Fragment>
<h1 className="logo">
<span>LOGO</span>
</h1>
</Fragment>
);
}
}
- ContainerMain
import React, { Component, Fragment } from "react";
import { Switch } from "react-router-dom";
//组件
import User from "../../views/user/index";
import UserAdd from "../../views/user/Add";
//私有路由组件
//私有组件方法
import PrivateRouter from "../privateRouter/index";
export default class ContainerMain extends Component {
constructor(prpos) {
super(prpos);
this.state = {};
}
render() {
return (
<Fragment>
<Switch>
<PrivateRouter exact path="/home/user/list" component={User}></PrivateRouter>
<PrivateRouter exact path="/home/user/add" component={UserAdd}></PrivateRouter>
</Switch>
</Fragment>
);
}
}
描述:这个页面是根据路由来展示不同的页面,里面引入私有组件方法匹配路由。
- PrivateRouter
import React from "react";
import { Route, Redirect } from "react-router-dom";
//获取token
import { getToken } from "../../utils/session";
const PrivateRouter = ({ component: Component, ...rest }) => {
return (
<Route
{...rest}
render={
(routePrpos) =>
getToken() ? <Component {...routePrpos} /> : <Redirect to="/" /> //判断token,是否重定向到登录页
}
/>
);
};
export default PrivateRouter;
描述:这个私有组件是react-router-dom官方提供的,我们在这个方法中做了路由重定向,防止通过路径访问。
- AsideMenu
import React, { Component, Fragment } from "react";
import { Link } from "react-router-dom";
//antd
import { UserOutlined } from "@ant-design/icons";
import { Menu } from "antd";
//路由
import Router from "../../router/index";
const { SubMenu } = Menu;
export default class AsideMenu extends Component {
constructor(props) {
super(props);
this.state = {};
}
// 无子级菜单处理
renderMenu = ({ title, key }) => {
return (
<Menu.Item key={key}>
<Link to={key}>{title}</Link>
</Menu.Item>
);
};
// 子级判断处理(递归)
renderSubMenu = ({ title, key, child }) => {
return (
<SubMenu key={key} icon={<UserOutlined />} title={title}>
{child &&
child.map((item) => {
return item.child && item.child.length > 0
? this.renderSubMenu(item)
: this.renderMenu(item);
})}
</SubMenu>
);
};
render() {
return (
<Fragment>
<Menu
mode="inline"
defaultSelectedKeys={["1"]}
defaultOpenKeys={["sub1"]}
style={{ height: "100%", borderRight: 0 }}
theme="dark"
>
{Router &&
Router.map((firstItem) => {
return firstItem.child && firstItem.child.length > 0
? this.renderSubMenu(firstItem)
: this.renderMenu(firstItem);
})}
</Menu>
</Fragment>
);
}
}
描述:LayoutAside组件中引入AsideMenu组件,AsideMenu组件主要是根据路由文件动态展示导航栏目录,其中renderMenu 、renderSubMenu这两个方法是最关键的,分别对应无子级菜单处理、子级判断处理(递归),然后再render函数中渲染,根据路由文件是否存在子路由来判断显示对应方法。
- Router
const router = [
{
title: "控制台",
icon: "home",
key: "/home",
},
{
title: "用户管理",
icon: "laptop",
key: "/home/user",
child: [
{
key: "/home/user/list",
title: "用户列表",
icon: "",
},
{
key: "/home/user/add",
title: "添加用户",
icon: "",
},
],
},
{
title: "部门管理",
icon: "bars",
key: "/home/navigation",
child: [
{
key: "/home/navigation/dropdown",
title: "部门列表",
icon: "",
},
{
key: "/home/navigation/menu",
title: "添加部门",
icon: "",
child: [
{
key: "/home/navigation/dropdown",
title: "部门列表",
icon: "",
},
{
key: "/home/navigation/menu",
title: "添加部门",
icon: "",
},
],
},
],
},
{
title: "职位管理",
icon: "edit",
key: "/home/entry",
child: [
{
key: "/home/entry/form/basic-form",
title: "职位列表",
icon: "",
},
{
key: "/home/entry/form/step-form",
title: "添加职位",
icon: "",
},
],
},
{
title: "请假",
icon: "info-circle-o",
key: "/home/about1",
},
{
title: "加班",
icon: "info-circle-o",
key: "/home/about",
},
];
export default router;
描述:统一放置路由地址的文件是以这样形式,判断是否有子路由是根据child判断的,所以这边修改要同时修改AsideMenu文件中的child判断。
App.js
import React, { Component } from "react";
import { Switch, Route, BrowserRouter } from "react-router-dom";
import "./app.scss";
// import Home from "./views/Home.js";
import Login from "./views/login/Index";
import Home from "./views/home/Index";
//私有组件
import PrivateRouter from "./components/privateRouter/index";
export default class App extends Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
return (
<div className="title">
<BrowserRouter>
<Switch>
<Route exact render={() => <Login />} path="/" />
<PrivateRouter component={Home} path="/home" />
{/* <Route exact render={() => <Home />} path="/home" /> */}
</Switch>
</BrowserRouter>
</div>
);
}
}
描述:这是页面路由的入口文件,放置登录路由、以及首页路由。
结束
- 目录结构