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 相关文章推荐
JScript的条件编译
May 29 Javascript
类似CSDN图片切换效果脚本
Sep 17 Javascript
jQuery 源码分析笔记(4) Ready函数
Jun 02 Javascript
jquery Mobile入门—多页面切换示例学习
Jan 08 Javascript
Jquery为a标签的href赋值实现代码
May 03 Javascript
node.js中的fs.unlink方法使用说明
Dec 15 Javascript
AngularJS中的表单简单入门
Jul 28 Javascript
Javascript中document.referrer隐藏来源的方法
Jan 16 Javascript
React Native中TabBarIOS的简单使用方法示例
Oct 13 Javascript
vue单页面打包文件大?首次加载慢?nginx带你飞,从7.5M到1.3M蜕变过程(推荐)
Jan 16 Javascript
详解如何构建一个Angular6的第三方npm包
Sep 07 Javascript
在vue项目中使用Jquery-contextmenu插件的步骤讲解
Jan 27 jQuery
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
MySQL GBK→UTF-8编码转换
2007/05/24 PHP
php array_unique之后json_encode需要注意
2011/01/02 PHP
PHP判断JSON对象是否存在的方法(推荐)
2016/07/06 PHP
你不知道的文件上传漏洞php代码分析
2016/09/29 PHP
php 自定义错误日志实例详解
2016/11/12 PHP
thinkphp 中的volist标签在ajax操作中的特殊性(推荐)
2018/01/15 PHP
JavaScript中把数字转换为字符串的程序代码
2013/06/19 Javascript
JavaScript字符串对象replace方法实例(用于字符串替换或正则替换)
2014/10/16 Javascript
浅谈JavaScript函数节流
2014/12/09 Javascript
浅谈javascript面向对象程序设计
2015/01/21 Javascript
学JavaScript七大注意事项【必看】
2016/05/04 Javascript
BootStrap实现邮件列表的分页和模态框添加邮件的功能
2016/10/13 Javascript
js注册时输入合法性验证方法
2017/10/21 Javascript
vue实现日历备忘录功能
2020/09/24 Javascript
js利用递归与promise 按顺序请求数据的方法
2019/08/30 Javascript
python栈的基本定义与使用方法示例【初始化、赋值、入栈、出栈等】
2019/10/24 Python
wxpython绘制音频效果
2019/11/18 Python
使用Python爬取弹出窗口信息的实例
2020/03/14 Python
Django中FilePathField字段的用法
2020/05/21 Python
jupyter notebook 写代码自动补全的实现
2020/11/02 Python
用python对excel进行操作(读,写,修改)
2020/12/25 Python
CSS3教程(1):什么是CSS3
2009/04/02 HTML / CSS
HTML5+CSS3应用详解
2014/02/24 HTML / CSS
HTML5进度条特效
2014/12/18 HTML / CSS
多视角3D可旋转的HTML5 Logo动画
2016/03/02 HTML / CSS
阿根廷旅游网站:almundo阿根廷
2018/02/12 全球购物
Maisons du Monde德国:法国家具和装饰的市场领导者
2019/07/26 全球购物
软件测试工程师面试问题精选
2016/10/28 面试题
个人综合鉴定材料
2014/05/23 职场文书
中药学专业求职信
2014/05/31 职场文书
手术室护士节演讲稿
2014/08/27 职场文书
高校自主招生校长推荐信
2015/03/23 职场文书
运动会开幕式新闻稿
2015/07/17 职场文书
Oracle11g r2 卸载干净重装的详细教程(亲测有效已重装过)
2021/06/04 Oracle
MySQL深度分页(千万级数据量如何快速分页)
2021/07/25 MySQL
分享几个实用的CSS代码块
2022/06/10 HTML / CSS