基于react实现无限分级菜单
在开发CMS(内容管理系统)系统时,一般都会用到一个侧边栏或者顶部的二级或者三级菜单,当点击或者鼠标悬浮时,菜单能够随之展开或收起。
本文纯粹为了练习一下react,因此我会在react环境下实现这么一个小组件:它假设了菜单数据来自于网络请求,并且仅实现无限分级菜单的核心功能(父子关系,展开与收起),至于样式则不是关注的重点。
分析&设计
既然要实现一个动态生成的无限分级菜单,最简单的切入思路就是分析一个静态的菜单:其DOM树是怎样构成的?
下面是一个典型的HTML结构:
<ul>
<li>
<h1>菜单1</h1>
<ul>
<li>
<h1>菜单1-1</h1>
<ul></ul>
</li>
</ul>
</li>
<li>
<h1>菜单2</h1>
<ul>
<li>
<h1>菜单2-1</h1>
<ul>
<li>
<h1>菜单2-1-1</h1>
<ul></ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
这是一个3级菜单,我们需要仔细观察它的构成规律:
- 首先<ul>代表了一个菜单列表,它里面包含了若干<li>代表其中1个菜单项。
- 每个<li>菜单项至少包含自己的标题,其次也应包含它下面的子菜单列表(也就是另一个<ul>)。
上述2个规则基本就是分级菜单的核心构思了,通过一个比较白话的描述可以这么理解:
要画一个菜单列表,那么就要去画它的每一个菜单项。
要画一个菜单项,那么就要画出标题,然后去画它的子菜单列表。
如果你反复的读上面的话,你可以感受到一种『递归的味道』。
没错,要根据菜单数据动态的画出一个无限分级的菜单是要用递归算法的。有意思的是,递归算法本身是深度优先的,而这恰好满足我们从上至下从外至内顺序追加HTML标签,从而最终构成完整的DOM树的编程思路。
数据结构&算法
程序设计=数据结构+算法。
因此,先用一个合理的数据结构来描述之前我们的构思,之后基于数据结构进行算法的实现,最终形成程序,这是我们正确的编程思路。
通常,菜单结构是服务端拼装的,它描述了菜单的父子和顺序关系,并且每个菜单拥有自己的唯一ID,这些都体现在我的render()方法中:
render() {
let data = [
{
menuId: 1,
name: '员工管理',
children: [
{
menuId: 3,
name: '添加员工',
children: []
},
{
menuId: 4,
name: '删除员工',
children: [
{
menuId: 6,
name: '按姓名删除',
children: []
},
{
menuId: 7,
name: '按工号删除',
children: []
}
]
}
],
},
{
menuId: 2,
name: '工资管理',
children: [
{
menuId: 5,
name: '修改工资',
children: []
}
],
},
]; return (
<div>
{this.generateMenu(data)}
</div>
);
}
最外层是一个菜单列表(Array),每个菜单项(Object)里有自己的标题,唯一ID,以及子菜单列表(Array)。
在render()方法里调用了我实现的递归算法generateMenu(data),根据上述数据结构和原理递归的生成了DOM树:
/**
* 递归生成菜单
* @param menuObj
* @returns {Array}
*/
generateMenu(menuObj) {
let vdom = []; if (menuObj instanceof Array) {
let list = [];
for (var item of menuObj) {
list.push(this.generateMenu(item));
}
vdom.push(
<ul key="single">
{list}
</ul>
);
} else {
vdom.push(
<li key={menuObj.menuId}>
<h1 onClick={this.onMenuClicked}>
{menuObj.name}
</h1>
{this.generateMenu(menuObj.children)}
</li>
);
}
return vdom;
}
- 第1个分支判断:如果当前对象是菜单列表(Array类型),那么应生成1个新的<ul>元素,并且递归画出每一个菜单项(Object类型)。
- 第2个分支判断:如果当前对象是菜单项(Object类型),那么应生成1个新的<li>元素,填充1个<h1>作为标题,其次递归画出它的子菜单列表。
最后,为了实现点击鼠标展开和收起菜单,我为每一个<h1>标签注册了onClick事件,当它们被点击时找到<h1>的兄弟<ul>元素(利用jquery搞定),修改其CSS display属性即可实现展现和隐藏其子菜单列表的效果了。
体验效果(react组件)
查看代码:https://github.com/owenliang/react/tree/master/component/MenuPage
查看demo:http://yuerblog.cc/wp-content/uploads/2016/11/output/#/menu-page
demo可以点击体验展开 or 收起
基于react实现无限分级菜单的更多相关文章
- 基于react可无限向内部添加节点的tree
这两天学习react,撸了一遍文档后开始自己动手写点东西. 正好从朋友那得到灵感,写一个小例子. 这个东西是这样的,就是点击的这个节点就往它里面添加一个child. 于是乎!我想到的就是用自调函数,递 ...
- 无限分级和tree结构数据增删改【提供Demo下载】
无限分级 很多时候我们不确定等级关系的层级,这个时候就需要用到无限分级了. 说到无限分级,又要扯到递归调用了.(据说频繁递归是很耗性能的),在此我们需要先设计好表机构,用来存储无限分级的数据.当然,以 ...
- C#使用二叉树算法设计一个无限分级的树表
效果图: 数据库: 操作树的示意图: 控制器代码: using Dw.Business; using Dw.Entity; using Dw.Utilities; using System; usin ...
- 前端基于react,后端基于.net core2.0的开发之路(1) 介绍
文章提纲目录 1.前端基于react,后端基于.net core2.0的开发之路(1) 介绍 2.前端基于react,后端基于.net core2.0的开发之路(2) 开发环境的配置,注意事项,后端数 ...
- 前端基于react,后端基于.net core2.0的开发之路(2) 开发环境的配置,注意事项,后端数据初始化
前端环境配置 项目介绍文章:前端基于react,后端基于.net core2.0的开发之路(1) 介绍 1.VSCode安装 下载地址:https://code.visualstudio.com/Do ...
- 放弃antd table,基于React手写一个虚拟滚动的表格
缘起 标题有点夸张,并不是完全放弃antd-table,毕竟在react的生态圈里,对国人来说,比较好用的PC端组件库,也就antd了.即便经历了2018年圣诞彩蛋事件,antd的使用者也不仅不减,反 ...
- 基于React实现的【绿色版电子书阅读器】,支持离线下载
代码地址如下:http://www.demodashi.com/demo/12052.html MyReader 绿色版电子书阅读器 在线地址:http://myreader.linxins.com ...
- JS组件系列——基于Bootstrap Ace模板的菜单和Tab页效果分享(你值得拥有)
前言:最近园子里多了许多谈语言.谈环境.谈逼格(格局)的文章,看看笑笑过后,殊不知其实都是然并卵.提升自己的技术才是王道.之前博主分享过多篇bootstrap组件的文章,引起了很多园友的关注和支持,看 ...
- 基于 React.js + Redux + Bootstrap 的 Ruby China 示例 (转)
一直学 REACT + METEOR 但路由部分有点问题,参考一下:基于 React.js + Redux + Bootstrap 的 Ruby China 示例 http://react-china ...
随机推荐
- node中子进程同步输出
管道 通过"child_process"模块fork出来的子进程都是返回一个ChildProcess对象实例,ChildProcess类比较特殊无法手动创建该对象实例,只能使用fo ...
- Node.js入门(一)
一.Node.js本质上是js的运行环境. 二.可以解析js代码(没有浏览器安全级的限制): 提供系统级的API:1.文件的读写 2.进程的管理 3.网络通信 三.可以关注的四个网站: 1.https ...
- Ajax部分
Ajax的概念 AJAX即"Asynchronous Javascript And XML"(异步JavaScript和XML),是一种用于创建快速动态网页的技术. 动态网页:是指 ...
- BPM配置故事之案例13-触发消息通知
老李:小明! 小明:--见你就没好事,又要我干嘛? 老李:额,小事小事,最近很多部门都觉得Boss的审批速度太慢了,能不能以后给审批人一个消息提醒? 小明:--有一种不太好的预感 老李:怎么,很困难么 ...
- 解决使用IE8打开ADFS 3.0登录页面
系统上线前一天,发现客户竟然有XP系统和2003系统,这些系统都不能访问外网.测试时,客户端是IE8,打开我们系统ADFS的登录页面,一直在Loading,无法打开,也不报错.后来通过fiddler跟 ...
- [转载]敏捷开发之Scrum扫盲篇
现在敏捷开发是越来越火了,人人都在谈敏捷,人人都在学习Scrum和XP... 为了不落后他人,于是我也开始学习Scrum,今天主要是对我最近阅读的相关资料,根据自己的理解,用自己的话来讲述S ...
- MySQL 优化之 MRR (Multi-Range Read:二级索引合并回表)
MySQL5.6中引入了MRR,专门来优化:二级索引的范围扫描并且需要回表的情况.它的原理是,将多个需要回表的二级索引根据主键进行排序,然后一起回表,将原来的回表时进行的随机IO,转变成顺序IO.文档 ...
- oracle常用的快捷键
最近在开发过程中,遇到一些麻烦,就是开发效率问题,有时候其他同事使用PLSQL 编程效率明显高于自己,观察了好久,才发现他使用PLSQL 已经很长时间了而且,他自己也在其中添加了好多快捷方式, 1.登 ...
- Phaser-游戏之旅
虽然这个小游戏逻辑不是很复杂,但为了熟悉Phaser这个游戏框架的使用方法所以就选择了它. 另外第一次在项目中尝试使用ES6,之后利用babel进行转换. 自动化构建:gulp(其他文件复制和解析) ...
- Java 开发主流 IDE 环境体验
前言 本来应该继续从 Oracle 官网搬砖的,但是随着示例代码越来越复杂,涉及的类库越来越多,使用 Vim 写 Java 代码就很力不从心了,是时候上 IDE 了.我最熟悉的 IDE 环境是 Ecl ...