在开发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实现无限分级菜单的更多相关文章

  1. 基于react可无限向内部添加节点的tree

    这两天学习react,撸了一遍文档后开始自己动手写点东西. 正好从朋友那得到灵感,写一个小例子. 这个东西是这样的,就是点击的这个节点就往它里面添加一个child. 于是乎!我想到的就是用自调函数,递 ...

  2. 无限分级和tree结构数据增删改【提供Demo下载】

    无限分级 很多时候我们不确定等级关系的层级,这个时候就需要用到无限分级了. 说到无限分级,又要扯到递归调用了.(据说频繁递归是很耗性能的),在此我们需要先设计好表机构,用来存储无限分级的数据.当然,以 ...

  3. C#使用二叉树算法设计一个无限分级的树表

    效果图: 数据库: 操作树的示意图: 控制器代码: using Dw.Business; using Dw.Entity; using Dw.Utilities; using System; usin ...

  4. 前端基于react,后端基于.net core2.0的开发之路(1) 介绍

    文章提纲目录 1.前端基于react,后端基于.net core2.0的开发之路(1) 介绍 2.前端基于react,后端基于.net core2.0的开发之路(2) 开发环境的配置,注意事项,后端数 ...

  5. 前端基于react,后端基于.net core2.0的开发之路(2) 开发环境的配置,注意事项,后端数据初始化

    前端环境配置 项目介绍文章:前端基于react,后端基于.net core2.0的开发之路(1) 介绍 1.VSCode安装 下载地址:https://code.visualstudio.com/Do ...

  6. 放弃antd table,基于React手写一个虚拟滚动的表格

    缘起 标题有点夸张,并不是完全放弃antd-table,毕竟在react的生态圈里,对国人来说,比较好用的PC端组件库,也就antd了.即便经历了2018年圣诞彩蛋事件,antd的使用者也不仅不减,反 ...

  7. 基于React实现的【绿色版电子书阅读器】,支持离线下载

    代码地址如下:http://www.demodashi.com/demo/12052.html MyReader 绿色版电子书阅读器 在线地址:http://myreader.linxins.com ...

  8. JS组件系列——基于Bootstrap Ace模板的菜单和Tab页效果分享(你值得拥有)

    前言:最近园子里多了许多谈语言.谈环境.谈逼格(格局)的文章,看看笑笑过后,殊不知其实都是然并卵.提升自己的技术才是王道.之前博主分享过多篇bootstrap组件的文章,引起了很多园友的关注和支持,看 ...

  9. 基于 React.js + Redux + Bootstrap 的 Ruby China 示例 (转)

    一直学 REACT + METEOR 但路由部分有点问题,参考一下:基于 React.js + Redux + Bootstrap 的 Ruby China 示例 http://react-china ...

随机推荐

  1. Linux 内核概述 - Linux Kernel

    Linux 内核学习笔记整理. Unix unix 已有40历史,但计算机科学家仍认为其是现存操作系统中最大和最优秀的系统,它已成为一种传奇的存在,历经时间的考验却依然声名不坠. 1973 年,在用 ...

  2. TinyWeb v1.0 正式完成第一个Release版本(功能基于 libuv 跨平台库)

    使用方法很简单,很容易融入现有项目,使现有项目拥有Web网站功能和WebSocket,以及Socket直连! 并且包含了一个跨平台(windows/linux)工具集合; 嗯,也挺棒的^,^ 在项目中 ...

  3. jsp中出现onclick函数提示Cannot return from outside a function or method

    在使用Myeclipse10部署完项目后,原先不出错的项目,会有红色的叉叉,JSP页面会提示onclick函数错误 Cannot return from outside a function or m ...

  4. 深入浅出JavaScript之原型链&继承

    Javascript语言的继承机制,它没有"子类"和"父类"的概念,也没有"类"(class)和"实例"(instanc ...

  5. [原]HAproxy 代理技术原理探究

    HAproxy 技术分享 简介 HAProxy是一款提供高可用性.负载均衡以及基于TCP(第四层)和HTTP(第七层)应用的代理软件 Features 1.免费 2.能够做到4层以上代理 3.高性能 ...

  6. JavaScript基础知识总结(三)

    JavaScript语法 七.循环语句 1.while 语法: while (exp) { //statements; } 说明:while (变量<=结束值) { 需执行的代码 } 例子: / ...

  7. java中Action层、Service层和Dao层的功能区分

    Action/Service/DAO简介: Action是管理业务(Service)调度和管理跳转的. Service是管理具体的功能的. Action只负责管理,而Service负责实施. DAO只 ...

  8. 对Maven、gradle、svn、spring 3.0 fragment、git的想法

    1.Maven Maven可以构建项目,采用pom方式配置主项目和其他需要引用的项目.同时可结合spring3.0的新特性web  fragment. 从现实出发,特别是对于管理不到位,程序员整体素质 ...

  9. 使用win10远程控制ubuntu16.04

    使用win10远程控制ubuntu16.04,网上很多需要安装xfce桌面的.今天介绍一下,不需要安装其他桌面,使用Ubuntu16.04自带桌面,漂亮美观. Ubuntu16.04端: 1.打开终端 ...

  10. VMware安装CentOS

    centos镜像地址:https://www.centos.org/download/ VMware版本:12.5.2 build-4638234 创建新的虚拟机 直接默认下一步 稍后安装操作系统-& ...