基于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 ...
随机推荐
- Summary of Critical and Exploitable iOS Vulnerabilities in 2016
Summary of Critical and Exploitable iOS Vulnerabilities in 2016 Author:Min (Spark) Zheng, Cererdlong ...
- Socket聊天程序——Common
写在前面: 上一篇记录了Socket聊天程序的客户端设计,为了记录的完整性,这里还是将Socket聊天的最后一个模块--Common模块记录一下.Common的设计如下: 功能说明: Common模块 ...
- C++ std::set
std::set template < class T, // set::key_type/value_type class Compare = less<T>, // set::k ...
- (系统架构)标准Web系统的架构分层
标准Web系统的架构分层 1.架构体系分层图 在上图中我们描述了Web系统架构中的组成部分.并且给出了每一层常用的技术组件/服务实现.需要注意以下几点: 系统架构是灵活的,根据需求的不同,不一定每一层 ...
- 07.LoT.UI 前后台通用框架分解系列之——强大的文本编辑器
LOT.UI分解系列汇总:http://www.cnblogs.com/dunitian/p/4822808.html#lotui LoT.UI开源地址如下:https://github.com/du ...
- UIViewController生命周期-完整版
一.UIViewController 的生命周期 下面带 (NSObject)的方法是NSObject提供的方法.其他的都是UIViewController 提供的方法. load (NSObje ...
- InnoDB体系结构学习笔记
后台线程 Master Thread 核心的后台线程,主要负责将缓冲池的数据异步刷新到磁盘,保证数据的一致性,包括(脏页的刷新).合并插入缓冲.(UNDO页的回收)等 IO Thread 4个writ ...
- 《Django By Example》第三章 中文 翻译 (个人学习,渣翻)
书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:第三章滚烫出炉,大家请不要吐槽文中 ...
- Python碎碎念
1. 如何添加路径 主要有以下两种方式: 1> 临时的 import sys sys.path.append('C:\Users\Victor\Desktop') 2> 永久的 在Linu ...
- SDWebImage源码解读之SDWebImageCache(下)
第六篇 前言 我们在SDWebImageCache(上)中了解了这个缓存类大概的功能是什么?那么接下来就要看看这些功能是如何实现的? 再次强调,不管是图片的缓存还是其他各种不同形式的缓存,在原理上都极 ...