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 相关文章推荐
使用jquery为table动态添加行的实现代码
Mar 30 Javascript
js判断屏幕分辨率的代码
Jul 16 Javascript
jQuery控制iFrame(实例代码)
Nov 19 Javascript
Javascript使用post方法提交数据实例
Aug 03 Javascript
jQuery采用连缀写法实现的折叠菜单效果
Sep 18 Javascript
漂亮! js实现颜色渐变效果
Aug 12 Javascript
AngularJS动态绑定ng-options的ng-model实例代码
Jun 21 Javascript
vue iView 上传组件之手动上传功能
Mar 16 Javascript
jQuery实现获取动态添加的标签对象示例
Jun 28 jQuery
node 标准输入流和输出流代码实例
Sep 19 Javascript
Vue 实现分页与输入框关键字筛选功能
Jan 02 Javascript
修改NPM全局模式的默认安装路径的方法
Dec 15 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
PHP 数组入门教程小结
2009/05/20 PHP
php使用strtotime和date函数判断日期是否有效代码分享
2013/12/25 PHP
zf框架的校验器使用使用示例(自定义校验器和校验器链)
2014/03/13 PHP
ThinkPHP使用心得分享-分页类Page的用法
2014/05/15 PHP
PHP递归遍历指定文件夹内的文件实现方法
2016/11/15 PHP
微信封装的调用微信签名包的类库
2017/06/08 PHP
thinkphp5实现微信扫码支付
2019/12/23 PHP
jQuery dialog 异步调用ashx,webservice数据的代码
2010/08/03 Javascript
javascript进行四舍五入方法汇总
2014/12/16 Javascript
使用jQuery jqPlot插件绘制柱状图
2014/12/18 Javascript
jQuery中nextAll()方法用法实例
2015/01/07 Javascript
jquery实现简单文字提示效果
2015/12/02 Javascript
BootStrap智能表单实战系列(六)表单编辑页面的数据绑定
2016/06/13 Javascript
Nodejs 搭建简单的Web服务器详解及实例
2016/11/30 NodeJs
JS正则表达式学习之贪婪和非贪婪模式实例总结
2016/12/26 Javascript
Angularjs使用指令做表单校验的方法
2017/03/31 Javascript
详解如何构建Angular项目目录结构
2017/07/13 Javascript
微信小程序实现下拉刷新和轮播图效果
2017/11/21 Javascript
详解在vue-cli项目下简单使用mockjs模拟数据
2018/10/19 Javascript
angularjs通过过滤器返回超链接的方法
2018/10/26 Javascript
JavaScript常见事件处理程序实例总结
2019/01/05 Javascript
Vue使用zTree插件封装树组件操作示例
2019/04/25 Javascript
vue使用transition组件动画效果的实例代码
2021/01/28 Vue.js
Python使用PyGreSQL操作PostgreSQL数据库教程
2014/07/30 Python
Python的Django框架下管理站点的基本方法
2015/07/17 Python
python实现读Excel写入.txt的方法
2018/04/29 Python
Python+Tensorflow+CNN实现车牌识别的示例代码
2019/10/11 Python
浅析python 定时拆分备份 nginx 日志的方法
2020/04/27 Python
飞利浦比利时官方网站:Philips比利时
2016/08/24 全球购物
欧洲高端品牌直销店:Fashionesta
2016/08/31 全球购物
澳大利亚办公室装修:JasonL Office Furniture
2019/06/25 全球购物
应用化学专业本科生求职信
2013/09/29 职场文书
捐款感谢信
2015/01/20 职场文书
2015年银行大堂经理工作总结
2015/04/24 职场文书
JavaScript数组 几个常用方法总结
2021/11/11 Javascript
Java tomcat手动配置servlet详解
2021/11/27 Java/Android