React 折腾记 - (1) React Router V4 和antd侧边栏的正确关联及动态title的实现
前言
一如既往,实战出真理.
有兴趣的可以瞧瞧,没兴趣的大佬请止步于此.
免得浪费您的时间
效果图
- 基于
antd
的sidebar
组件封装
折腾记的技术栈选型
Mobx & mobx-react
(用起来感觉良好的状态管理器)React 16.4.2
(从这个起步,用新不用旧)React Router V4
(如上)antd
(版本追求如上 , 阿里出品的UI框架)styled-components
(不想写单独的样式文件,用这个是棒棒的,用过都说好)webpack 4.16.5
(版本追求如上)
实现思路
实现思路
- 自行维护一份静态路由表
- 结合路由的
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不到会返回nullif (pathname.match(childitem.path)) {this.setState({openKeys: [item.key],selectedKeys: [childitem.key]});// 设置titledocument.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 => (<SubMenukey={item.key}title={<span><Icon type={item.title.icon} /><span>{item.title.text}</span></span>}>{item.children &&item.children.map(menuItem => (<Itemkey={menuItem.key}onClick={() => {// 设置高亮的itemthis.setState({ selectedKeys: [menuItem.key] });// 设置文档标题document.title = menuItem.text;}}><Link to={menuItem.path}>{menuItem.text}</Link></Item>))}</SubMenu>));return (<Sidercollapsiblebreakpoint="lg"collapsed={collapsed}onCollapse={onCollapse}trigger={collapsed}><Logo collapsed={collapsed} /><MenusubMenuOpenDelay={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
也行...萝卜青菜各有所爱
答疑
- 小伙伴留言说要看我的目录如何构建的,其实和常规的搭建差不多,如下
如何生成漂亮的目录树
alias gdtree="tree -I 'node_modules|dist|.git|.vscode|.DS_Store|.idea' -L 2 -a"
我直接写到环境文件里了, -L
就是遍历的层级, -a
是所有文件(包括隐藏), -I
是正则忽略
├── .babelrc # babel配置
├── .browserslistrc #浏览器的兼容范围
├── .editorconfig # 基础规范
├── .eslintignore # eslint忽略
├── .eslintrc # eslint 配置
├── .gitignore
├── .postcssrc.js # postcss配置
├── .prettierrc # 格式化代码的配置文件
├── README.md
├── build # webpack的构建目录
│ ├── webpack.base.config.js # 通用的webpack配置,可以理解为common,开发和生产都依赖,比如插件等
│ ├── webpack.development.js # 开发模式专有,热更新,反向代理啥的
│ └── webpack.production.js # 尽可能的压缩切割,抽离样式为CSS文件什么的
├── jsconfig.json # 用来映射webpack alias 的,这样vscode下才能智能提示alias的路径
├── package.json
├── public
│ ├── favicon.png
│ └── index.html
├── src
│ ├── App.css
│ ├── App.js # 根组件
│ ├── PrivateRoute.js # 私有路由,对Route的封装
│ ├── assets # 静态资源
│ ├── components # 通用组件
│ ├── index.js # webpack的主入口
│ ├── pages # 页面组件
│ ├── services # api的封装,以及汇总地方
│ ├── store # 状态管理
│ └── utils # 公用的代码片段,比如一些函数什么的
├── tests # 存放jest单元测试的目录
│ └── union
└── yarn.lock复制代码
总结
公司最近打算重构整个后台管理系统;把老的两个系统整合在一起....emmm,
单打独斗的好处(bei shang)就是技术选型可以自己把握
说做就做,用最新的webpack4
搭了个架子,开始折腾(因为比较新,更新依赖很容易出问题)....
等项目完毕再把脚手架放出来,估计webpack
5都出来了..
有人肯定会说,官方有现成的antd pro
为嘛不用..我看了跟dva高度结合,不喜欢,那就自己搭架子
之前用vue
和ng
都是整个系统布局自己写一遍...这次试试用现成的侧边栏来实现
有不对之处请留言,看到会及时修正,谢谢阅读.
React 折腾记 - (1) React Router V4 和antd侧边栏的正确关联及动态title的实现相关推荐
- React 16.x折腾记 - (1) React Router V4 和antd侧边栏的正确关联及动态title的实现
前言 一如既往,实战出真理,有兴趣的可以瞧瞧,没兴趣的大佬请止步于此. 效果图 基于antd的sidebar组件封装 折腾记的技术栈选型 Mobx & mobx-react(用起来感觉良好的状 ...
- React 折腾记 - (4) 侧边栏联动Tabs菜单-增强版(结合Mobx)
前言 有小伙伴留言有前进后退没法联动的问题.我仔细梳理下了. 简化了代码逻辑和代码量,重写了一遍,执行逻辑和上个版本有所差异; 上个版本 :React 折腾记 - (3) 结合Mobx实现一个比较靠谱 ...
- hitchhiker部署_Hitchhiker的React Router v4指南:无限远的递归路径!
hitchhiker部署 Welcome to the third part of the Hitchhiker's Guide to React Router v4. In this article ...
- [React Router v4] Intercept Route Changes
If a user has entered some input, or the current Route is in a "dirty" state and we want t ...
- [React Router v4] Conditionally Render a Route with the Switch Component
We often want to render a Route conditionally within our application. In React Router v4, the Route ...
- hitchhiker部署_《 Hitchhiker的React Router v4指南》:路由配置的隐藏值
hitchhiker部署 Welcome to the Hitchhiker's Guide to React Router v4, Part IV! 欢迎来到< React Router v4 ...
- 关于React Router v4的虚张声势指南
In this article, we'll cover the important things you can quickly learn to be informed and confident ...
- 使用React Router v4的嵌套路由
React Router v4 introduced a new declarative, component based approach to routing. With that approac ...
- react router v4 简介
最近使用react router 遇到一个问题:当对某个路由添加参数的时候/list/:app 这列路由,点击这个路由以后再点击其他路由,location地址就追加到后面,问不是replace. /l ...
最新文章
- 某程序员遭遇奇葩事:辞退自己的leader竟然命令自己回前公司,给前同事讲代码!...
- 概率分布--------离散概率分布和连续概率分布
- TextureView+MediaPlayer实现在线短视频播放
- java file源码_java File源码理解,探索File路径
- 安装linux6.10 I386系统教程,一看就懂的Centos6.10安装教程
- php异步轮询如何实现,深入剖析JavaScript异步之事件轮询
- 开发人员不得不知的MySQL索引和查询优化
- SCCM 2012 R2 从入门到精通 Part11 系统推送(2)
- M1 Mac 档案的临时暂存区工具: Yoink
- “蓝桥杯”练习系统练习题答案(自己做的)
- 5%和1%精度的贴片电阻标称阻值表
- windows 技巧篇-解除共享文件夹占用方法,解决共享文件被占用导致不可修改问题,查看共享文件被谁占用方法
- CREO:CREO软件之零件【渲染】之对三维零件实现渲染图文教程之详细攻略
- Arista携手思科、瞻博网络 计划打造面向云的交换与路由设备
- 如何在命令行打开mysql
- 蓝桥杯 填写乘法算式
- OSChina 周三乱弹 ——学哪种编程语言能保住一头秀发?
- 高通Android随身WIFI屏蔽商家远程控制断网
- 网络地址192.168.10.0;子网掩码255.255.255.128 计算
- OCP-1Z0-053-200题-168题-528
热门文章
- extjs 月份选择控件_Ext JS 4实现带week(星期)的日期选择控件(实战二)
- 序列每天从0开始_序列化、反序列化原理和Protobuf实现机制
- 【grpc】[Python] A file with this name is already in the pool
- linux有名管道大小,Linux中的pipe与named pipe(FIFO),即管道和命名管道
- ubuntu命令行语法_Linux中重定向命令行的总结(ubuntu学习第三讲)
- Gatling性能测试(一)
- 这些面试细节90%的人都没注意!怪不得简历白投了...
- Matlab与MySQL数据库交互基本操作
- mysql 性能问题_mysql 性能问题
- php查询对象是否有某个属性可用,JavaScript 判断对象中是否有某属性的常用方法...