广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >JavaScript树形组件实现无限级树形结构
  • 666
分享到

JavaScript树形组件实现无限级树形结构

2024-04-02 19:04:59 666人浏览 八月长安
摘要

目录​一、问题研究的背景和意义​​二、详细设计方案​​三、源代码实现(Java版)​​四、思考与总结​(1)XML层次结构(2)UL-LI层次结构(3)TABLE层次结构​一、问题研

​一、问题研究的背景和意义​

WEB应用程序开发领域,基于ajax技术的javascript树形组件已经被广泛使用,它用来在html页面上展现具有层次结构的数据项。目前市场上常见的JavaScript框架及组件库中均包含自己的树形组件,例如Jquery、Ext js等,还有一些独立的树形组件,例如dhtmlxTree等,这些树形组件完美的解决了层次数据的展示问题。展示离不开数据,树形组件主要利用Ajax技术从服务器端获取数据源,数据源的格式主要包括JSON、XML等,而这些层次数据一般都存储在数据库中。“无限级树形结构”,顾名思义,没有级别的限制,它的数据通常来自数据库中的无限级层次数据,这种数据的存储表通常包括id和parentId这两个字段,以此来表示数据之间的层次关系。现在问题来了,既然树形组件的数据源采用JSON或XML等格式的字符串来组织层次数据,而层次数据又存储在数据库的表中,那么如何建立起树形组件与层次数据之间的关系,换句话说,如何将数据库中的层次数据转换成对应的层次结构的JSON或XML格式的字符串,返回给客户端的JavaScript树形组件?这就是我们要解决的关键技术问题。本文将以目前市场上比较知名的Ext JS框架为例,讲述实现无限级树形结构的方法,该方法同样适用于其它类似的JavaScript树形组件。

Ext JS框架是富客户端开发中出类拔萃的框架之一。在Ext的UI组件中,树形组件无疑是最为常用的组件之一,它用来实现树形结构的视图。Treenode用来实现静态的树形结构,AsyncTreeNode用来实现动态的异步加载树形结构,后者最为常用,它通过接收服务器端返回来的JSON格式的数据,动态生成树形结构节点。动态生成树有两种思路:一种是一次性生成全部树节点,另一种是逐级加载树节点(利用Ajax,每次点击节点时查询下一级节点)。对于大数据量的树节点来说,逐级加载是比较合适的选择,但是对于小数据量的树节点来说,一次性生成全部节点应该是最为合理的方案。在实际应用开发中,一般不会遇到特别大数据量的场景,所以一次性生成全部树节点是我们重点研究的技术点,也就是本文要解决的关键技术问题。本文以基于Ext JS的应用系统为例,讲述如何将数据库中的无限级层次数据一次性在界面中生成全部树节点(例如在界面中以树形方式一次性展示出银行所有分支机构的信息),同时对每一个层次的节点按照某一属性和规则排序,展示出有序的树形结构。

解决一次性构造无限级树形结构的问题,可以拓展出更多的应用场景,例如树形结构表格TreeGrid,一次性生成树形表格,对树形表格进行完整分页,对表格列进行全排序;或者可以利用本文的思路扩展出其他的更复杂的应用场景。

先看两个图例,有个直观上的认识:

图一,银行分支机构树形结构:

图二,树形结构表格:

​二、详细设计方案​

让我们先看两段代码片段:

文件一,branchTree.html (Ext树形组件页面)

Ext.onReady(
function(){
   var  tree = new Ext.tree.TreePanel({
      height: 300,
      width: 400,
      animate:true,
      enableDD:true,
      containerScroll: true,
      rootVisible: false,
      frame: true,
      // getBranch.do请求服务器返回多级树形结构的JSON字符串
       loader: new Ext.tree.TreeLoader({dataUrl:'getBranch.do'}),  
      root : new Ext.tree.AsyncTreeNode({id:'0',text:'根结点'})  
     });      
     tree.expandAll();
 }
);

文件二,branchTreeJSON.jsp (接收getBranch.do请求,返回多级树形结构的JSON字符串)

<%
// 读取银行分支机构的层次数据
List result = DataAccess.getBankInfoList();
// 将层次数据转换为多叉树对象(本文下面会详细介绍该数据结构的实现方法)
Node root = ExtTreeHelper.createExtTree(result);  
%>                                              
[
<%=root.toString()%> <!-- 以JSON的形式返回响应数据,Ext.tree.TreeLoader会根据此数据生成树形结构 -->
]

以上两个程序文件是一次性生成无限级树形结构所必须的,其中最为关键的部分就是如何生成一个无限级的树形结构JSON字符串,返回给客户端的Ext树形组件。

对于银行分支机构来说,需要返回类似如下的JSON串:

{
 id: '100000',
 text: '廊坊银行总行',
 children: [
   {
     id: '110000',
     text: '廊坊分行',
     children: [
       {
         id: '113000',
         text: '廊坊银行开发区支行',
         leaf: true
       },
       {
         id: '112000',
         text: '廊坊银行解放道支行',
         children: [
           {
             id: '112200',
             text: '廊坊银行三大街支行',
             leaf: true
           },
           {
             id: '112100',
             text: '廊坊银行广阳道支行',
             leaf: true
           }
         ]
       },
       {
         id: '111000',
         text: '廊坊银行金光道支行',
         leaf: true
       }
     ]
   }
 ]
}

同时还需要对树中每一个层次的节点按照某一属性(比如分支机构编号)进行排序,以展示出有序的树形结构。

现在可以把问题概括为:

  • 1、 把数据库中的层次数据转换成多级树形结构的JSON格式的字符串
  • 2、 对树中每一个层次的节点按照某一属性(比如分支机构编号)进行排序

下面介绍解决问题的思路:

在数据结构这门课中,我们都学过树,无限级树形结构就可以抽象成一种多叉树结构,即每个节点下包含多个子节点的树形结构,首先就需要把数据库中的层次数据转换成多叉树结构的对象树,也就是构造出一棵多叉树。

有了数据结构,还要实现相应的算法,我们需要实现两种算法:

  • 1、兄弟节点横向排序算法,对隶属于同一个父节点下面的所有直接子节点按照某一节点属性和规则进行排序,保持兄弟节点横向有序;
  • 2、先序遍历算法,递归打印出无限级JSON字符串。

概括起来分为三步:

  • 1、 构造无序的多叉树结构
  • 2、 实现兄弟节点横向排序方法
  • 3、 实现先序遍历方法,打印出JSON字符串

如图所示:

​三、源代码实现(Java版)​

实现这样一颗树,需要设计两个类:树类(MultipleTree)、节点类(Node);排序时还需要一个比较器类(NodeIDComparator);为了方便演示,还需要构造一些假的层次数据,因此还需要建一个构造假数据的类(VirtualDataGenerator),以下代码拷贝出来之后可直接运行测试

package test;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Collections;


public class MultipleTree {
public static void main(String[] args) {
  // 读取层次数据结果集列表  
 List dataList = VirtualDataGenerator.getVirtualResult();

 // 节点列表(映射表,用于临时存储节点对象)
 HashMap nodeList = new HashMap();
 // 根节点
 Node root = null;
 // 将结果集存入映射表(后面将借助映射表构造多叉树)
 for (Iterator it = dataList.iterator(); it.hasNext();) {
  Map dataRecord = (Map) it.next();
  Node node = new Node();
  node.id = (String) dataRecord.get("id");
  node.text = (String) dataRecord.get("text");
  node.parentId = (String) dataRecord.get("parentId");
  nodeList.put(node.id, node);
 }
 // 构造无序的多叉树
 Set entrySet = nodeList.entrySet();
 for (Iterator it = entrySet.iterator(); it.hasNext();) {
  Node node = (Node) ((Map.Entry) it.next()).getValue();
  if (node.parentId == null || node.parentId.equals("")) {
   root = node;
  } else {
   ((Node) nodeList.get(node.parentId)).addChild(node);
  }
 }
 // 输出无序的树形结构的JSON字符串
 System.out.println(root);
 // 对多叉树进行横向排序
 root.sortChildren();
 // 输出有序的树形结构的JSON字符串
 System.out.println(root);

 // 程序输出结果如下:
 //
 // 无序的树形结构(格式化后的结果,可使用JSON格式化工具查看,例如  Http://jsonviewer.stack.hu/ 在线查看器):  
 //  {
  //   id : '100000',  
  //   text : '廊坊银行总行',  
 //   children : [
 //     {
  //     id : '110000',  
  //     text : '廊坊分行',  
 //     children : [
 //       {
  //       id : '113000',  
  //       text : '廊坊银行开发区支行',  
 //       leaf : true
 //       },
 //       {
  //       id : '111000',  
  //       text : '廊坊银行金光道支行',  
 //       leaf : true
 //       },
 //       {
  //       id : '112000',  
  //       text : '廊坊银行解放道支行',  
 //       children : [
 //         {
  //         id : '112200',  
  //         text : '廊坊银行三大街支行',  
 //         leaf : true
 //         },
 //         {
  //         id : '112100',  
  //         text : '廊坊银行广阳道支行',  
 //         leaf : true
 //         }
 //       ]
 //       }
 //     ]
 //     }
 //   ]
 //  }

 // 有序的树形结构(格式化后的结果):
 //  {
  //   id : '100000',  
  //   text : '廊坊银行总行',  
 //   children : [
 //     {
  //     id : '110000',  
  //     text : '廊坊分行',  
 //     children : [
 //       {
  //       id : '111000',  
  //       text : '廊坊银行金光道支行',  
 //       leaf : true
 //       },
 //       {
  //       id : '112000',  
  //       text : '廊坊银行解放道支行',  
 //       children : [
 //         {
  //         id : '112100',  
  //         text : '廊坊银行广阳道支行',  
 //         leaf : true
 //         },
 //         {
  //         id : '112200',  
  //         text : '廊坊银行三大街支行',  
 //         leaf : true
 //         }
 //       ]
 //       },
 //       {
  //       id : '113000',  
  //       text : '廊坊银行开发区支行',  
 //       leaf : true
 //       }
 //     ]
 //     }
 //   ]
 //  }  

}

}


class Node {

public String id;


public String text;


public String parentId;


private List children = new ArrayList();

// 添加孩子节点
public void addChild(Node node) {
 children.add(node);
}

// 先序遍历,拼接JSON字符串
public String toString() {
 String result = "{" + "id : '" + id + "'" + ", text : '" + text + "'";
 if (children.size() != 0) {
  result += ", children : [";
  for (int i = 0; i < children.size(); i++) {
    result += ((Node) children.get(i)).toString() + ",";    
  }
  result = result.substring(0, result.length() - 1);
  result += "]";
 } else {
  result += ", leaf : true";
 }
 return result + "}";
}

// 兄弟节点横向排序
public void sortChildren() {
 if (children.size() != 0) {
  // 对本层节点进行排序(可根据不同的排序属性,传入不同的比较器,这里 传入ID比较器)
  Collections.sort(children, new NodeIDComparator());
    // 对每个节点的下一层节点进行排序    
  for (int i = 0; i < children.size(); i++) {
   ((Node) children.get(i)).sortChildren();
  }
 }
}

}


class NodeIDComparator implements Comparator {
// 按照节点编号比较
public int compare(Object o1, Object o2) {
 int j1 = Integer.parseInt(((Node) o1).id);
 int j2 = Integer.parseInt(((Node) o2).id);
 return (j1 < j2 ? -1 : (j1 == j2 ? 0 : 1));
}
}


class VirtualDataGenerator {
// 构造无序的结果集列表,实际应用中,该数据应该从数据库中查询获得;
public static List getVirtualResult() {
 List dataList = new ArrayList();

 HashMap dataRecord1 = new HashMap();
 dataRecord1.put("id", "112000");
 dataRecord1.put("text", "廊坊银行解放道支行");
 dataRecord1.put("parentId", "110000");

 HashMap dataRecord2 = new HashMap();
 dataRecord2.put("id", "112200");
 dataRecord2.put("text", "廊坊银行三大街支行");
 dataRecord2.put("parentId", "112000");

 HashMap dataRecord3 = new HashMap();
 dataRecord3.put("id", "112100");
 dataRecord3.put("text", "廊坊银行广阳道支行");
 dataRecord3.put("parentId", "112000");

 HashMap dataRecord4 = new HashMap();
 dataRecord4.put("id", "113000");
 dataRecord4.put("text", "廊坊银行开发区支行");
 dataRecord4.put("parentId", "110000");

 HashMap dataRecord5 = new HashMap();
 dataRecord5.put("id", "100000");
 dataRecord5.put("text", "廊坊银行总行");
 dataRecord5.put("parentId", "");

 HashMap dataRecord6 = new HashMap();
 dataRecord6.put("id", "110000");
 dataRecord6.put("text", "廊坊分行");
 dataRecord6.put("parentId", "100000");

 HashMap dataRecord7 = new HashMap();
 dataRecord7.put("id", "111000");
 dataRecord7.put("text", "廊坊银行金光道支行");
 dataRecord7.put("parentId", "110000");

 dataList.add(dataRecord1);
 dataList.add(dataRecord2);
 dataList.add(dataRecord3);
 dataList.add(dataRecord4);
 dataList.add(dataRecord5);
 dataList.add(dataRecord6);
 dataList.add(dataRecord7);

 return dataList;
}
}

好了,通过上面的代码,就可以实现多叉树的兄弟节点横向排序和先序遍历了,实现了将层次数据转换为有序无限级树形结构JSON字符串的目的。

在实际的项目中,可以把上面的有效代码融入其中,或者在此基础上进行一些扩展:

  • 1、 实现对指定层次的排序(例如只排序第一层的节点,或者只排序某一父节点下的所有子节点)
  • 2、 遍历输出树形结构时可以加入判断条件过滤掉某些节点
  • 3、 实现节点的删除功能
  • 4、 在节点类中增加一个父节点的引用,就可以计算出某一节点所处的级别
  • 5、 在不支持层次查询的数据库应用系统中使用该算法实现相同的效果

​四、思考与总结​

这篇文章的重点是如何构造有序的无限级的树形结构JSON字符串,一次性生成树形结构,而不是利用Ajax的方式,反复向服务器端发送请求,一级接一级的加载树节点。

既然可以构造无限级的JSON字符串,那么也可以根据这个思路构造无限级的XML字符串,或者构造具有层次结构的UL – LI组合(用UL - LI来展示树形结构),或者构造具有层次结构的TABLE(用TABLE来展示树形结构)。

如下所示:

(1)XML层次结构

<nodeGroup id="100000" name="廊坊银行总行">
<nodeGroup id="110000" name="廊坊分行">
 <node id="113000" name="廊坊银行开发区支行">  
 </node>
 <node id="111000" name="廊坊银行金光道支行">  
 </node>
 <nodeGroup id="112000" name="廊坊银行解放道支行">
    <node id="112200" name="廊坊银行三大街支行">    
  </node>
    <node id="112100" name="廊坊银行广阳道支行">    
  </node>
 </nodeGroup>
</nodeGroup>
</nodeGroup>

(2)UL - LI 层次结构

<ul>
<li>廊坊银行总行</li>
<ul>
 <li>廊坊分行</li>
 <ul>
    <li>廊坊银行开发区支行</li>      
    <li>廊坊银行解放道支行</li>
    <ul>
     <li>廊坊银行三大街支行</li>
     <li>廊坊银行广阳道支行</li>
     </ul>  
   <li>廊坊银行金光道支行</li>
  </ul>  
  </ul>  
</ul>

(3)TABLE层次结构

<table>
<tr><td>廊坊银行总行</td></tr>
<tr><td>&nbsp;&nbsp;廊坊分行</td></tr>
<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;廊坊银行开发区支行</td></tr>
<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;廊坊银行解放道支行</td></tr>
<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;廊坊银行三大街支行</td></tr>
<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;廊坊银行广阳道支行</td></tr>
<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;廊坊银行金光道支行</td></tr>
</table>

另外对TreeGrid树形表格也有一定的价值:

  • 1、 一次性构造树形表格,实现数据分级展示
  • 2、 通过更换比较器,实现对不同表格列的全排序(全排序指的是对所有页的数据进行排序,而不是只对当前页的数据排序;排序规则与oracle数据库中的层次查询类似,即兄弟节点横向排序)
  • 3、 实现对树形表格的完整分页(每次分页时,只取固定数目的第一层节点,之后调用toString方法,展示出完整条数的分级数据,即每页的记录条数是不固定的,但必须是完整的树形结构)

 到此这篇关于JavaScript树形组件实现无限级树形结构的文章就介绍到这了,更多相关JavaScript无限级树形结构内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: JavaScript树形组件实现无限级树形结构

本文链接: https://www.lsjlt.com/news/142480.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • JavaScript树形组件实现无限级树形结构
    目录​一、问题研究的背景和意义​​二、详细设计方案​​三、源代码实现(Java版)​​四、思考与总结​(1)XML层次结构(2)UL-LI层次结构(3)TABLE层次结构​一、问题研...
    99+
    2022-11-13
  • VUE 无限层级树形数据结构显示的实现
    目录组件递归调用使用render方法在做项目中,会遇到一些树形的数据结构,常用在左侧菜单导航,或者评论引用等地方,这种数据结构有个特点是不知道它会嵌套多少层,所以用template去...
    99+
    2022-11-12
  • vue递归组件实现树形结构
    本文实例为大家分享了vue递归组件实现树形结构,供大家参考,具体内容如下 一、递归组件 什么是递归组件?简单来说就是在组件中内使用组件本身。函数自己调用自己。很多情况下我们呢刷数据的...
    99+
    2022-11-13
  • Vue2组件tree如何实现无限级树形菜单
    小编给大家分享一下Vue2组件tree如何实现无限级树形菜单,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!How to run ...
    99+
    2022-10-19
  • VUE无限层级树形数据结构显示怎么实现
    这篇文章主要讲解了“VUE无限层级树形数据结构显示怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“VUE无限层级树形数据结构显示怎么实现”吧!文章中用...
    99+
    2022-10-19
  • Vue实现无限级树形选择器
    目录简单实现下样式递归渲染定义参数实现点击事件完整代码前言: 想要在 Vue 中实现一个这样的无限级树形选择器其实并不难,关键点在于利用 递归组件 和 ...
    99+
    2022-11-13
  • JS实现树形结构与数组结构相互转换并在树形结构中查找对象
    总是有很多需求是关于处理树形结构的,所以不得不总结几个常见操作的写法。 首先假设有一个树形结构数据如下 var tree=[ { 'id': '1', 'name...
    99+
    2022-11-13
  • QtQTreeWidget树形结构实现代码
    Qt中实现树形结构可以使用QTreeWidget类,也可以使用QTreeView类,QTreeWidget继承自QTreeView类。树形效果如下图所示: 这是怎么实现的呢?还有点...
    99+
    2022-11-12
  • vue开发树形结构组件(组件递归)
    本文实例为大家分享了vue开发树形结构组件的具体代码,供大家参考,具体内容如下 需求 一个页面,要显示商品分类,同时每个分类下面还拥有若干子类,子类也可以有子类。 要实现全选单选,子...
    99+
    2022-11-12
  • JavaScript平铺数组转树形结构的实现示例
    目录后台丢来了1w条数据 递归方式非递归方式总结后台丢来了1w条数据 千算万算,还是没有逃过,后台真的就上万条数据一次丢给前端了。好吧,好在还不是10w条。如下,后台返回的是这样的...
    99+
    2022-11-12
  • JavaScript数组扁平转树形结构数据(Tree)的实现
    前言 之前面试有遇到过这个问题,面试官问:如何把一个数组数据扁平,然后转化为Tree结构数据,工作中刚好也用到了,在这里总结一下。 需求大致如下 把这个数组转为树形结构数据(Tree...
    99+
    2022-11-13
    JavaScript数组扁平转树形结构 javascript扁平数组转树形结构
  • 纯css如何实现树形结构
    这篇文章将为大家详细讲解有关纯css如何实现树形结构,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。纯css实现属性结构css实现属性结构的思路是利用伪类实现树形结构连接线,如果想实现点击展开和收缩以及复选...
    99+
    2023-06-08
  • Qt QTreeWidget树形结构怎么实现
    本篇内容介绍了“Qt QTreeWidget树形结构怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Qt中实现树形结构可以使...
    99+
    2023-06-21
  • 如何将JavaScript将数组转为树形结构
    1.需求 后台给了一个这样的数据让咱前端去转换为树形结构(没有重复数据)。不多说,先来看看给了一个怎样的数组数据,转换为怎样的树形结构。 服务器传过来的数组 const ar...
    99+
    2022-11-12
  • vue递归实现树形组件
    本文实例为大家分享了vue递归实现树形组件的具体代码,供大家参考,具体内容如下 1. 先来看一下效果: 2. 代码部分 (myTree.vue) 图片可以自己引一下自己的图片,或者...
    99+
    2022-11-13
  • springboot+mybatis plus实现树形结构查询
    目录背景 使用场景 设计思路 递归模型 实现代码 注意事项 总结 背景 实际开发过程中经常需要查询节点树,根据指定节点获取子节点列表,以下记录了获取节点树的操作,以备不时之需。 使...
    99+
    2022-11-12
  • SpringBoot+MyBatisPlus+MySQL8实现树形结构查询
    本文实例为大家分享了SpringBoot+MyBatisPlus+MySQL8实现树形结构查询,供大家参考,具体内容如下 场景: 今天在实现权限功能模块时,需要将查询的权限数据,以树...
    99+
    2022-11-12
  • vue如何实现树形结构表格
    这篇文章主要讲解了“vue如何实现树形结构表格”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“vue如何实现树形结构表格”吧!在el-table中,支持树类型的数据的显示。当 row 中包含&...
    99+
    2023-07-04
  • java递归实现树形结构数据
    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、树形结构是什么?二、实现方案1、stream流递归实现1.1 实体类1.2 实现类 2、jdk1.7以下实现2.1 节点类2.2 实现类...
    99+
    2023-08-18
    java 数据库 mysql
  • 使用JavaScript怎么将数组转为树形结构
    本篇文章给大家分享的是有关使用JavaScript怎么将数组转为树形结构,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。1.需求后台给了一个这样的数据让咱前端去转换为树形结构(没...
    99+
    2023-06-15
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作