前言
如标题所言,动态更改标题,关联菜单栏
依旧如以前,实战出真理,理论的文章太多,自行去搜索
有兴趣的可以瞧瞧,没兴趣的大佬请止步于此.免得浪费您的时间
效果图
- 基于
antd
的sidebar
组件封装
实现思路
实现思路
- 自行维护一份静态路由表
- 结合路由的
history
对象的pathanme
- 在组件渲染完毕的情况下,再去遍历路由表,通过
setState
重新渲染侧边栏 - 为什么不在组件初始化的时候就设置,那这样对于404的路由没法控制
react-router-dom v4
虽然提供了全局404组件,但是history
里面没有代表404的状态
实现目标
- 点击侧边栏的子菜单会改变标题,对应的item也会高亮
- 直接修改路由,初次加载等会自动展开对应的分组,高亮对应的子项
- 不匹配的路由不展开和高亮任何
能学到啥
我尽量注释,而收获见仁见智了
我的思路? 我的的代码姿势? 仅供参考
实现代码
基础版
- 静态路由表一份
export const sidebarData = [
{
key: 'group0',
title: {
icon: 'dashboard',
text: '数据分析'
},
children: [
{
key: '1',
text: '数据监控',
path: '/dashboard/monitor'
},
{
key: '2',
text: '数据分析',
path: '/dashboard/analyze'
}
]
},
{
key: 'group1',
title: {
icon: 'play-circle',
text: '音频管理'
},
children: [
{
key: '6',
text: '声兮列表',
path: '/voice/sxlist'
},
{
key: '7',
text: '回声列表',
path: '/voice/calllist'
}
]
},
{
key: 'group2',
title: {
icon: 'schedule',
text: '活动中心'
},
children: [
{
key: '11',
text: '活动列表',
path: '/active/list'
},
{
key: '12',
text: '新建活动',
path: '/active/add'
}
]
},
{
key: 'group3',
title: {
icon: 'apple-o',
text: 'APP管理'
},
children: [
{
key: '16',
text: '移动交互',
path: '/appmanage/interaction'
},
{
key: '17',
text: '回声列表',
path: '/test'
},
{
key: '18',
text: '用户列表',
path: '/user/list'
}
]
},
{
key: 'group4',
title: {
icon: 'safety',
text: '安全中心'
},
children: [
{
key: '21',
text: '举报处理',
path: '/safety/report'
},
{
key: '22',
text: '广播中心',
path: '/safety/broadcast'
}
]
},
{
key: 'group5',
title: {
icon: 'user',
text: '系统设置'
},
children: [
{
key: '26',
text: '个人设置',
path: '/user/setting'
},
{
key: '27',
text: '用户列表',
path: '/user/list'
}
]
},
{
key: 'group6',
title: {
icon: 'info-circle',
text: '平台设置'
},
children: [
{
key: '31',
text: '用户协议',
path: '/platform/license'
},
{
key: '32',
text: '帮助中心',
path: '/platform/help'
}
]
}
];
export const groupKey = sidebarData.map(item=>item.key);
复制代码
- sidebar
import React, { Component } from 'react';
import { Link, withRouter } from 'react-router-dom';
// antd
import { Layout, Menu, Icon } from 'antd';
const { Sider } = Layout;
const { SubMenu, Item } = Menu;
import { sidebarData, groupKey } from 'pages/Layout/SidebarData';
// Logo组件
import Logo from 'pages/Layout/Logo';
@withRouter
class Sidebar extends Component {
constructor(props) {
super(props);
// 初始化置空可以在遍历不到的时候应用默认值
this.state = {
openKeys: [''],
selectedKeys: [''],
rootSubmenuKeys: groupKey,
itemName: ''
};
}
setDefaultActiveItem = ({ location }) => {
const { pathname } = location;
sidebarData.map(item => {
if (item.pathname) {
// 做一些事情,这里只有二级菜单
}
// 因为菜单只有二级,简单的做个遍历就可以了
if (item.children && item.children.length > 0) {
item.children.map(childitem => {
// 为什么要用match是因为 url有可能带参数等,全等就不可以了
// 若是match不到会返回null
if (pathname.match(childitem.path)) {
this.setState({
openKeys: [item.key],
selectedKeys: [childitem.key]
});
// 设置title
document.title = childitem.text;
}
});
}
});
};
componentDidMount = () => {
// 设置菜单的默认值
this.setDefaultActiveItem(this.props);
};
OpenChange = openKeys => {
console.log(openKeys);
const latestOpenKey = openKeys.find(
key => this.state.openKeys.indexOf(key) === -1
);
console.log(latestOpenKey);
if (this.state.rootSubmenuKeys.indexOf(latestOpenKey) === -1) {
this.setState({ openKeys });
} else {
this.setState({
openKeys: latestOpenKey ? [latestOpenKey] : [...openKeys]
});
}
};
render() {
const { openKeys, selectedKeys } = this.state;
const { collapsed, onCollapse } = this.props;
const SideTree = sidebarData.map(item => (
<SubMenu
key={item.key}
title={
<span>
<Icon type={item.title.icon} />
<span>{item.title.text}</span>
</span>
}>
{item.children &&
item.children.map(menuItem => (
<Item
key={menuItem.key}
onClick={() => {
// 设置高亮的item
this.setState({ selectedKeys: [menuItem.key] });
// 设置文档标题
document.title = menuItem.text;
}}>
<Link to={menuItem.path}>{menuItem.text}</Link>
</Item>
))}
</SubMenu>
));
return (
<Sider
collapsible
breakpoint="lg"
collapsed={collapsed}
onCollapse={onCollapse}
trigger={collapsed}>
<Logo collapsed={collapsed} />
<Menu
subMenuOpenDelay={0.3}
theme="dark"
openKeys={openKeys}
selectedKeys={selectedKeys}
mode="inline"
onOpenChange={this.OpenChange}>
{SideTree}
</Menu>
</Sider>
);
}
}
export default Sidebar;
复制代码
collapsed
,onCollapse
这些是控制侧边栏缩小的,接受的是外部的props
拓展版思路
举一反三,同样我们同在可以在静态路由添加鉴权,比如某个路由仅限某些用户访问!
这样鉴权机制可以做到很细致化,但是对应的判断逻辑也会多起来,看业务改了
也可以维护过渡效果,添加对应的字段,然后每次访问不同URL的时候更改过渡效果
以上的都需要依赖状态管理器,来维护,因为涉及到不同组件的通讯,mobx
也可以,redux
也行...萝卜青菜各有所爱
总结
公司最近打算重构整个后台管理系统;把老的两个系统整合在一起....emmm,
单打独斗的好处(bei shang)就是技术选型可以自己把握
说做就做,用最新的webpack4
搭了个架子,开始折腾(因为比较新,更新依赖很容易出问题)....
等项目完毕再把脚手架放出来,估计webpack
5都出来了..
技术选型 Mobx + React 16.4 + React Router V4 + antd + styled-components
有人肯定会说,官方有现成的antd pro
为嘛不用..我看了跟dva高度结合,不喜欢,自定写更符合需求
之前用vue
和ng
都是整个系统布局自己写一遍...这次试试用现成的侧边栏来实现
有不对之处请留言,看到会及时修正,谢谢阅读.