bootstrap-treeview实现多级树形菜单 后台JSON格式如何组织?


Posted in Javascript onJuly 26, 2019

树形列表菜单的数据组织形式一般有两种:一种是一次性向服务器请求所有节点的数据,一种是先请求根目录的节点,当用户点击该节点时,再去请求该节点的子叶节点的数据。这里我们的需求是第一种。

bootstrap-treeview实现多级树形菜单 后台JSON格式如何组织?

树形菜单是我们经常会用到的一种菜单展现方式,这里我推荐bootstrap-treeview,它是一款效果非常酷的基于bootstrap的jQuery多级列表树插件。该jQuery插件基于Twitter Bootstrap,以简单和优雅的方式来显示一些继承树结构,如视图树、列表树等。

前端页面的编写,比较简单,故简略描述,我们着重将后端如何按照要求组织返回所需的Json。

使用方法

首先要在页面中引入依赖的css样式和 bootstrap-treeview.js文件。

<!-- Required Stylesheets -->
<link href="./css/bootstrap.css" rel="external nofollow" rel="stylesheet">
 
<!-- Required Javascript -->
<script src="./js/jquery.js"></script>
<script src="./js/bootstrap-treeview.js"></script>

可以使用任何HTML DOM元素来作为该列表树的容器:

<div id="tree"></div>

调用

<script type="text/javascript">
 $(function() {$.ajax({
  type: "Get",
  url: "doctype/FarmDoctypeLoadTreeNodes.do",
  data: {id: ""},
  dataType: "json",
  success: function (result) {
  $("#tree").treeview({
  data: result.nodes,  // 数据源
  levels:1, //设置继承树默认展开的级别
  showTags: true, //是否在每个节点右边显示tags标签。tag值必须在每个列表树的data结构中给出
  onNodeSelected: function (event, data) {
   /* console.log(data); */
   /* alert(data.nodeId); */
   window.location = basePath + "webtype/view"
 + data.id + "/Pub1.html"; 
  }
   }); 
  },
  error: function () {
  alert("加载失败!")
  }
 }); 
 
 });
</script>

数据源要求的数据格式:

var tree = [
  {
  text: "Parent 1",
  tags: ['2'],
  nodes: [
   {
   text: "Child 1",
   tags: ['3'],
   nodes: [
   {
   text: "Grandchild 1",
   tags: ['1']
   },
   {
   text: "Grandchild 2",
   tags: ['1']
   }
   ]
   },
   {
   text: "Child 2",
   tags: ['1']
   }
  ]
  },
  {
  text: "Parent 2",
   tags: ['1']
  },
  {
  text: "Parent 3",
   tags: ['1']
  },
  {
  text: "Parent 4",
   tags: ['1']
  },
  {
  text: "Parent 5",
   tags: ['1']
  }
  ];

看到这个数据结构,我们首先想到的是数据结构中的二叉树。欧拉,我们不妨可以把它理解成,这样的数据结构:

bootstrap-treeview实现多级树形菜单 后台JSON格式如何组织?

创建一个实例,组织所需要的数据结构的json.

public class BootstrapUiTreeNode implements Serializable {
 private static final long serialVersionUID = 1L;
 static final Logger log = Logger.getLogger(BootstrapUiTreeNode.class);
 
 private String id;
 private String parentId;
 private String text;
 
 //子叶节点
 private List<BootstrapUiTreeNode> nodes = new ArrayList<>();
 
 //统计该节点分类下文档的数量
 private List<String> tags = new ArrayList<>(); // tags: ['NUM']
 
 public BootstrapUiTreeNode(String id, String parentId, String text) {
 super();
 this.id = id;
 this.parentId = parentId;
 this.text = text;
 }
 
 
 public BootstrapUiTreeNode(String id, String parentId, String text, List<BootstrapUiTreeNode> nodes) {
 super();
 this.id = id;
 this.parentId = parentId;
 this.text = text;
 this.nodes = nodes;
 }
 
 
 public String getParentId() {
 return parentId;
 }
 
 
 public void setParentId(String parentId) {
 this.parentId = parentId;
 }
 
 
 public String getId() {
 return id;
 }
 
 public void setId(String id) {
 this.id = id;
 }
 
 public String getText() {
 return text;
 }
 
 public void setText(String text) {
 this.text = text;
 }
 
 public List<BootstrapUiTreeNode> getNodes() {
 return nodes;
 }
 
 public void setNodes(List<BootstrapUiTreeNode> nodes) {
 this.nodes = nodes;
 }
 
 
 public List<String> getTags() {
 return tags;
 }
 
 
 public void setTags(List<String> tags) {
 this.tags = tags;
 }
 
 
 
 /**
 * 加载第一层树节点 父节点的根目录的父id必须为"NONE",包含字段名ID,PARENTID,NAME
 * 
 * @param parentId
 *  父亲节点id
 * @param SortTitle
 *  排序字段index
 * @param tableTitle
 *  表名index
 * @param id_title
 *  表id的index
 * @param parentId_title
 *  表parentid的index
 * @param name_title
 *  表name的index
 * @param icon_title
 */
 public static List<Map<String, Object>> queryTreeNodeOne(String parentId, String SortTitle, String tableTitle, String id_title,
 String parentId_title, String name_title) {
 if (StringUtils.isEmpty(parentId)) {
 parentId = "NONE";
 }
 DataResult nodeResult = null;
 DBSort sort = new DBSort("a." + SortTitle, "ASC");
 DataQuery query = DataQuery.getInstance("1", 
 id_title
 + ","
 + parentId_title
 + " as "
 + parentId_title
 + ","
 + name_title
 + " as "
 + name_title,
 tableTitle + " a");
 query.setPagesize(100);
 query.addSort(sort);
 DataQuerys.wipeVirus(parentId);
 query.setSqlRule("and " + parentId_title + "='" + parentId + "'");
 try {
 nodeResult = query.search();
 } catch (SQLException e) {
 log.error(e.getMessage());
 }
 return nodeResult.getResultList();
 }
 
 public static List<TypeBrief> getPopTypesForReadDoc() {
 DataQuery query = DataQuery.init(new DataQuery(),
 "(SELECT a.NAME as NAME,a.SORT as SORT, a.ID as ID, a.READPOP as READPOP,a.WRITEPOP AS WRITEPOP, a.AUDITPOP AS AUDITPOP, a.PARENTID AS PARENTID, (SELECT COUNT(B1.ID) FROM FARM_DOC B1 LEFT JOIN FARM_RF_DOCTYPE B2 ON B1.ID = B2.DOCID LEFT JOIN FARM_DOCTYPE B3 ON B3.ID = B2.TYPEID WHERE B1.STATE='1' and B3.TREECODE LIKE CONCAT(A.TREECODE,'%') AND B1.STATE='1') AS NUM,f.oid as OID,f.FUNTYPE as FUNTYPE FROM farm_doctype AS a left join FARM_DOCTYPE_POP as f on f.TYPEID=a.ID WHERE 1 = 1 AND (TYPE = '1' OR TYPE = '3') AND PSTATE = '1' ) AS e",
 "NAME,ID,PARENTID,NUM,OID,READPOP,AUDITPOP,WRITEPOP,FUNTYPE,SORT");
 query.setPagesize(1000);
 query.setNoCount();
 query.setCache(Integer.valueOf(0), CACHE_UNIT.second);
 query.addSort(new DBSort("SORT", "ASC"));
 try {
 DataResult result = query.search();
 //利用反射获取对象集合
 return result.getObjectList(TypeBrief.class);
 } catch (SQLException e) {
 log.error(e.toString());
 return new ArrayList<TypeBrief>();
 }
 }
 
 
 
 /**
 * 遍历集合获得对象
 * 
 * @param nodeList
 * @return
 */
 public static List<BootstrapUiTreeNode> findNode(List<TypeBrief> typeBriefs, List<Map<String, Object>> data, String id_title,
 String parentId_title, String name_title) {
 List<BootstrapUiTreeNode> nodeList = new ArrayList<>();
 try {
 for (Map<String, Object> node : data) {
 if (node.get(id_title) == null) {
 continue;
 }
 BootstrapUiTreeNode item = new BootstrapUiTreeNode(node.get(id_title).toString(), 
 node.get(parentId_title).toString(), node.get(name_title).toString());
 //统计该节点下分类的文档数
 for(TypeBrief typeBrief : typeBriefs) {
 if(typeBrief.getId().equals(node.get(id_title).toString())) {
 item.getTags().add(typeBrief.getNum() + "");
 break;
 }
 }
 nodeList.add(item);
 }
 } catch (Exception e) {
 throw new RuntimeException(e);
 }
 return nodeList;
 }
 
 /**
 * 先用递归构造除第一层几个根节点外的类多叉树结构
 * @param node
 * @param parentId
 * @param sortTitle
 * @param tableTitle
 * @param id_title
 * @param parentId_title
 * @param name_title
 * @return
 */
 public static BootstrapUiTreeNode createSubtreeTreeNodes(List<TypeBrief> typeBriefs, BootstrapUiTreeNode node, String parentId, String sortTitle, String tableTitle, String id_title,
 String parentId_title, String name_title) {
 
 //获取该根节点下的所有子节点
 List<Map<String, Object>> data = queryTreeNodeOne(parentId, sortTitle, tableTitle, id_title, parentId_title, name_title);
 List<BootstrapUiTreeNode> roots = findNode(typeBriefs, data, id_title, parentId_title, name_title);
 
 if(null != roots && roots.size() > 0) {
 //递归继续查询
 for(BootstrapUiTreeNode child : roots) {
 BootstrapUiTreeNode treeNode = createSubtreeTreeNodes(typeBriefs, child, child.getId(), sortTitle, tableTitle, id_title, parentId_title, name_title);
 node.getNodes().add(treeNode);
 }
 
 } else {
 node.setNodes(null); 
 }
 
 return node;
 }
 
 /**
 * 补上第一层的几个根节点
 * @param parentId
 * @param sortTitle
 * @param tableTitle
 * @param id_title
 * @param parentId_title
 * @param name_title
 * @return
 * 
 * 注意:所以会存在叶子节点中的nodes没有数据的情况,这个时候会出现叶子节点是可以伸缩的,
 * 因为nodes属性就是一个对象数组,它会被认为它还有子节点,其实是没有的。
 * 
 */
 public static List<BootstrapUiTreeNode> createTreeNodes(String parentId, String sortTitle, String tableTitle, String id_title,
 String parentId_title, String name_title) {
 //统计所有节点分类对应的文档数目
 List<TypeBrief> typeBriefs = getPopTypesForReadDoc();
 
 List<BootstrapUiTreeNode> nodes = new ArrayList<>();
 //查询第一层根节点
 List<Map<String, Object>> data = queryTreeNodeOne(parentId, sortTitle, tableTitle, id_title, parentId_title, name_title);
 List<BootstrapUiTreeNode> treeNodes = findNode(typeBriefs, data, id_title, parentId_title, name_title);
 
 for(BootstrapUiTreeNode node : treeNodes) {
 BootstrapUiTreeNode treeNode = createSubtreeTreeNodes(typeBriefs, node, node.getId(), sortTitle, tableTitle, id_title, parentId_title, name_title);
 nodes.add(treeNode);
 }
 
 return nodes;
 }
}

控制器:

@RequestMapping("/FarmDoctypeLoadTreeNodes")
 @ResponseBody
 public Map<String, Object> loadTreeNodes(DataQuery query, HttpServletRequest request, String id) {
 query = EasyUiUtils.formatGridQuery(request, query);
 try {
 List<BootstrapUiTreeNode> treeNodes = BootstrapUiTreeNode.createTreeNodes(id, "SORT", "FARM_DOCTYPE", "ID", "PARENTID", "NAME");
 return ViewMode.getInstance().putAttr("nodes", treeNodes).returnObjMode();
 } catch (Exception e) {
 log.error(e.getMessage());
 return ViewMode.getInstance().setError(e.getMessage()).returnObjMode();
 }
 }

访问结果:

bootstrap-treeview实现多级树形菜单 后台JSON格式如何组织?

最终树形菜单效果:

bootstrap-treeview实现多级树形菜单 后台JSON格式如何组织?

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
让元素在网页中可拖动示例代码
Aug 13 Javascript
javascript实现倒计时(精确到秒)
Jun 26 Javascript
JavaScript判断数组是否存在key的简单实例
Aug 03 Javascript
jQuery实现页面倒计时并刷新效果
Mar 13 Javascript
详解Vue 方法与事件处理器
Jun 20 Javascript
node+koa实现数据mock接口的方法
Sep 20 Javascript
React Native中的RefreshContorl下拉刷新使用
Oct 09 Javascript
基于JSONP原理解析(推荐)
Dec 04 Javascript
解决Vue 项目打包后favicon无法正常显示的问题
Sep 01 Javascript
JS基于Location实现访问Url、重定向及刷新页面的方法分析
Dec 03 Javascript
JavaScript使用百度ECharts插件绘制饼图操作示例
Nov 26 Javascript
vuex刷新后数据丢失的解决方法
Oct 18 Javascript
bootstrap-table+treegrid实现树形表格
Jul 26 #Javascript
Vue实现商品分类菜单数量提示功能
Jul 26 #Javascript
vue实现滑动切换效果(仅在手机模式下可用)
Jun 29 #Javascript
微信小程序设置滚动条过程详解
Jul 25 #Javascript
vuejs移动端实现div拖拽移动
Jul 25 #Javascript
vue实现拖拽的简单案例 不超出可视区域
Jul 25 #Javascript
vue实现一拉到底的滑动验证
Jul 25 #Javascript
You might like
S900/ ETON E1-XM 收音机
2021/03/02 无线电
探讨:如何通过stats命令分析Memcached的内部状态
2013/06/14 PHP
CI框架验证码CAPTCHA辅助函数用法实例
2014/11/05 PHP
php使用ffmpeg向视频中添加文字字幕的实现方法
2016/05/23 PHP
浅谈laravel数据库查询返回的数据形式
2019/10/21 PHP
jQuery 表格插件整理
2010/04/27 Javascript
jQuery之按钮组件的深入解析
2013/06/19 Javascript
javascript面向对象快速入门实例
2015/01/13 Javascript
DOM基础教程之使用DOM + Css
2015/01/20 Javascript
优化RequireJS项目的相关技巧总结
2015/07/01 Javascript
javascript中闭包(Closure)详解
2016/01/06 Javascript
JavaScript开发者必备的10个Sublime Text插件
2016/02/27 Javascript
深入理解事件冒泡(Bubble)和事件捕捉(capture)
2016/05/28 Javascript
Google 地图API Map()构造器详解
2016/08/06 Javascript
jQuery获取select选中的option的value值实现方法
2016/08/29 Javascript
基于JavaScript实现右键菜单和拖拽功能
2016/11/28 Javascript
AngularJS实现的2048小游戏功能【附源码下载】
2018/01/03 Javascript
利用js-cookie实现前端设置缓存数据定时失效
2019/06/18 Javascript
微信小程序中网络请求缓存的解决方法
2019/12/29 Javascript
python实现排序算法
2014/02/14 Python
用Python遍历C盘dll文件的方法
2015/05/06 Python
Python网络编程中urllib2模块的用法总结
2016/07/12 Python
Python的多维空数组赋值方法
2018/04/13 Python
关于tf.reverse_sequence()简述
2020/01/20 Python
Python参数传递机制传值和传引用原理详解
2020/05/22 Python
css3 transform 3d 使用css3创建动态3d立方体(html5实践)
2013/01/06 HTML / CSS
Hotels.com泰国:酒店预订网站
2019/11/20 全球购物
生物学学生自我评价
2014/01/17 职场文书
护理专业自荐信范文
2014/02/26 职场文书
会计与出纳自荐书范文
2014/03/16 职场文书
大学新闻系应届生求职信
2014/06/02 职场文书
公司门卫岗位职责范本
2014/07/08 职场文书
高职教师先进事迹材料
2014/08/24 职场文书
法定代表人授权委托书范文
2014/09/22 职场文书
合伙购房协议样本
2014/10/06 职场文书
2015年幼儿园后勤工作总结
2015/04/25 职场文书