目录规范:
1. 子组件都存放在components>父名文件夹中,例如components>sandbox>SideMenu.js
2. 页面级组件(带路由)都存放在views>父名文件夹中,例如views>sandbox>NewsSandBox.js;若有NewsSandBox组件中的页面级组件,就在sandbox下再创建文件夹放入,例如views>sandbox>home>home.js
路由模块安装指令:cnpm i --save-dev react-router-dom@5.2.0
src > App.js
import React from 'react'
import IndexRouter from './router/IndexRouter';
import './App.css'
function App() {
return <IndexRouter></IndexRouter>
}
export default App;
src > router > IndexRouter.js
import React from 'react'
import { HashRouter, Route, Switch, Redirect } from 'react-router-dom'
import Login from '../views/login/Login'
import NewsSandBox from '../views/sandbox/NewsSandBox'
export default function IndexRouter() {
return (
<HashRouter>
<Switch>
{/* 制定规则 */}
<Route path="/login" component={Login} />
{/* 制定规则 如果存过token 就显示NewsSandBox页面 否则重定向去login页面*/}
<Route path="/" render={() =>
localStorage.getItem("token") ?
<NewsSandBox></NewsSandBox> :
<Redirect to="/login" />
} />
</Switch>
</HashRouter>
)
}
src > views > sandbox > NewsSandBox.js
import React from 'react'
import { Switch, Route, Redirect } from 'react-router-dom'
import SideMenu from '../../components/sandbox/SideMenu'
import TopHeader from '../../components/sandbox/TopHeader'
import Home from './home/Home'
import NoPermission from './nopermission/NoPermission'
import RightList from './right-manage/RightList'
import RoleList from './right-manage/RoleList'
import UserList from './user-manage/UserList'
export default function NewsSandBox() {
return (
<div>
<SideMenu></SideMenu>
<TopHeader></TopHeader>
<Switch>
{/* 制定规则 如果走的是以下预约的4个路径... */}
<Route path="/home" component={Home} />
<Route path="/user-manage/list" component={UserList} />
<Route path="/right-manage/role/list" component={RoleList} />
<Route path="/right-manage/right/list" component={RightList} />
{/* 制定规则 如果不加exact 那么任何带有/的路径都会被带到/home */}
<Redirect from="/" to="/home" exact />
{/* 和上一行搭配使用——如果你走的不是我们预定好的路由... */}
<Route path="*" component={NoPermission} />
</Switch>
</div>
)
}
=============================使用antd后==============================
src > App.css
@import '~antd/dist/antd.css';
src > views > sandbox > NewsSandBox.js
import React from 'react'
import { Switch, Route, Redirect } from 'react-router-dom'
import SideMenu from '../../components/sandbox/SideMenu'
import TopHeader from '../../components/sandbox/TopHeader'
import Home from './home/Home'
import NoPermission from './nopermission/NoPermission'
import RightList from './right-manage/RightList'
import RoleList from './right-manage/RoleList'
import UserList from './user-manage/UserList'
//css
import './NewsSandBox.css'
//antd
import { Layout } from 'antd';
const { Content } = Layout;
export default function NewsSandBox() {
return (
<Layout>
<SideMenu></SideMenu>
<Layout className="site-layout">
<TopHeader></TopHeader>
<Content
className="site-layout-background"
style={{
margin: '24px 16px',
padding: 24,
minHeight: 280,
}}
>
<Switch>
{/* 制定规则 如果走的是以下预约的4个路径... */}
<Route path="/home" component={Home} />
<Route path="/user-manage/list" component={UserList} />
<Route path="/right-manage/role/list" component={RoleList} />
<Route path="/right-manage/right/list" component={RightList} />
{/* 制定规则 如果不加exact 那么任何带有/的路径都会被带到/home */}
<Redirect from="/" to="/home" exact />
{/* 和上一行搭配使用——如果你走的不是我们预定好的路由... */}
<Route path="*" component={NoPermission} />
</Switch>
</Content>
</Layout>
</Layout>
)
}
src > views > sandbox > NewsSandBox.css
#components-layout-demo-custom-trigger .trigger {
padding: 0 24px;
font-size: 18px;
line-height: 64px;
cursor: pointer;
transition: color 0.3s;
}
#components-layout-demo-custom-trigger .trigger:hover {
color: #1890ff;
}
#components-layout-demo-custom-trigger .logo {
height: 32px;
margin: 16px;
background: rgba(255, 255, 255, 0.3);
}
.site-layout .site-layout-background {
background: #fff;
}
/* 高为100%占满屏幕 */
#root,.ant-layout{
height: 100%;
}
src > components > sandbox > SideMenu.js
import React, { useEffect, useState } from 'react'
import { Layout, Menu } from 'antd';
import './index.css';
import { withRouter } from 'react-router-dom';
import {
UserOutlined,
VideoCameraOutlined,
UploadOutlined,
SettingOutlined
} from '@ant-design/icons';
import axios from 'axios';
const { Sider } = Layout;
const { SubMenu } = Menu;
//模拟数组解构 现已无用
// const menuList = [
// {
// key: '/home',//只是用做key值
// title: '首页',
// icon: <UserOutlined />
// },
// {
// key: '/user-manage',//只是用做key值
// title: '用户管理',
// icon: <VideoCameraOutlined />,
// children: [
// {
// key: '/user-manage/list',//只是用做key值
// title: '用户列表',
// icon: <VideoCameraOutlined />,
// }
// ]
// },
// {
// key: '/right-manage',//只是用做key值
// title: '权限管理',
// icon: <UploadOutlined />,
// children: [
// {
// key: '/right-manage/role/list',//只是用做key值
// title: '角色列表',
// icon: <UploadOutlined />,
// },
// {
// key: '/right-manage/right/list',//只是用做key值
// title: '权限列表',
// icon: <UploadOutlined />,
// },
// ]
// },
// ]
//前端定义iconList
const iconList = {
'/home': <UserOutlined />,
'/user-manage': <VideoCameraOutlined />,
'/user-manage/list': <VideoCameraOutlined />,
'/right-manage': <UploadOutlined />,
'/right-manage/role/list': <UploadOutlined />,
'/right-manage/right/list': <SettingOutlined />
}
function SideMenu(props) {
const [menu, setMenu] = useState([])
//改从后端获取路由数组
useEffect(() => {
axios.get('http://localhost:3000/rights?_embed=children').then(
res => {
console.log(res.data);
setMenu(res.data)
}
)
}, [])
//根据是否item有pagepermisson这个字段决定是否将这个item渲染在侧边栏
const checkPagePermission = (item) => {
return item.pagepermisson === 1
}
const renderMenu = (menuList) => {
return menuList.map(item => {
//item.children?表示:item.children为undefined的话就不继续执行了
if (item.children?.length > 0 && checkPagePermission(item)) {
return <SubMenu key={item.key} icon={iconList[item.key]} title={item.title}>
{renderMenu(item.children)}
</SubMenu>
} else {
return checkPagePermission(item) && <Menu.Item key={item.key} icon={iconList[item.key]}
onClick={
() => {
props.history.push(item.key)
}
}>{item.title}</Menu.Item>
}
})
}
//刷新页面也不改变已选中的侧边栏 defaultSelectedKeys-选中的 defaultOpenKeys-展开并高亮的
console.log(props.location.pathname);
const selectedKeys = [props.location.pathname]// /right-manage/role/list
const openKeys = ["/" + props.location.pathname.split('/')[1]]// /right-manage
return (
<Sider trigger={null} collapsible collapsed={false} >
<div style={{ display: "flex", height: "100%", flexDirection: 'column' }}>
<div className="logo" >全球新闻发布管理系统</div>
<div style={{ flex: 1, overflow: "auto" }}>
<Menu theme="dark" mode="inline"
selectedKeys={selectedKeys}
defaultOpenKeys={openKeys}
>
{/* <Menu.Item key="1" icon={<UserOutlined />}>
nav 1
</Menu.Item>
<Menu.Item key="2" icon={<VideoCameraOutlined />}>
nav 2
</Menu.Item>
<Menu.Item key="3" icon={<UploadOutlined />}>
nav 3
</Menu.Item>
<SubMenu key="sub4" icon={<SettingOutlined />} title="Navigation Three">
<Menu.Item key="9">Option 9</Menu.Item>
<Menu.Item key="10">Option 10</Menu.Item>
<Menu.Item key="11">Option 11</Menu.Item>
<Menu.Item key="12">Option 12</Menu.Item>
</SubMenu> */}
{renderMenu(menu)}
</Menu>
</div>
</div>
</Sider>
)
}
export default withRouter(SideMenu)
src > components > sandbox > TopHeader.js
import React, { useState } from 'react'
import { Layout, Avatar } from 'antd';
import {
MenuUnfoldOutlined,
MenuFoldOutlined,
UserOutlined
} from '@ant-design/icons';
import { Menu, Dropdown } from 'antd';
const { Header } = Layout;
export default function TopHeader() {
const [collapsed, setCollapsed] = useState(false)
const changeCollapsed = () => {
setCollapsed(!collapsed)
}
const menu = (
<Menu>
<Menu.Item key="1">
超级管理员
</Menu.Item>
<Menu.Item key="2" danger>
退出
</Menu.Item>
</Menu>
);
return (
<Header className="site-layout-background" style={{ padding: "0 16px" }}>
{
collapsed ?
<MenuUnfoldOutlined onClick={changeCollapsed} /> :
<MenuFoldOutlined onClick={changeCollapsed} />
}
<div style={{ float: "right" }}>
<span>欢迎admin</span>
<Dropdown overlay={menu}>
<Avatar size="large" icon={<UserOutlined />} />
</Dropdown>
</div>
</Header>
)
}