个人博客导航页(点击右侧链接即可打开个人博客):大牛带你入门技术栈
0、学完本文你或许可以收获
-
感受一个树工具从初始逐步优化完善的过程
-
树工具封装的设计思考与实现思路
-
最后收获一款拿来即用的树工具源代码
对于前端树组件有一定了解和使用过的同学可直接跳跃到第3章节开始。
1、树长什么样 ?
前端的树组件大多数情况下出现在后端的管理系统中,比如我们常见的菜单树、机构树、某某分类树、树表格等。大致像下方图片所展示的这样。
菜单树
机构树
org_tree.png
树表格
大致上来说,前端树的展现形式就是上面3张图所列的几种形式。而这种前端树组件的展现构成需要依赖于后端返回的数据格式。
2、数据格式
结合我自身使用过的前端树组件来说,大致可以分为如下两种。
列表形式
[
{ id:1, pId:0, name:"父节点1"}
{ id:11, pId:1, name:"父节点11"},
{ id:111, pId:11, name:"叶子节点111"},
{ id:112, pId:11, name:"叶子节点112"},
{ id:113, pId:11, name:"叶子节点113"},
{ id:114, pId:11, name:"叶子节点114"},
{ id:12, pId:1, name:"父节点12"},
{ id:121, pId:12, name:"叶子节点121"},
{ id:122, pId:12, name:"叶子节点122"},
{ id:123, pId:12, name:"叶子节点123"},
{ id:124, pId:12, name:"叶子节点124"}
]
树形结构
[{ name:"父节点1",
children: [
{
name:"父节点11",
children: [
{ name:"叶子节点111"},
{ name:"叶子节点112"},
{ name:"叶子节点113"},
{ name:"叶子节点114"}
]
},
{
name:"父节点12",
children: [
{ name:"叶子节点121"},
{ name:"叶子节点122"},
{ name:"叶子节点123"},
{ name:"叶子节点124"}
]
}
]
}]
本文所讲的树工具封装主要是针对第二种数据格式树形结构来说,因为第一种本身不需要特殊处理,也就不存在什么封装,就是简单的列表查询展示,与一般数据列表数据格式的区别是多了数据ID与父ID属性提供给前端进行树组件的构造。
而第二种是要在列表形式的数据格式上进行转换,形成如上所示的树形结构。但是,我们发现里面没有数据ID与父ID属性,why ? 因为后端完成了数据层面树结构的构造工作,前端树组件再无需根据这两个属性进行树结构的判断构建,直接展示就OK,当然也不绝对,最终还得看前端的树组件是否需要。
但一般都会保留这两个属性,因为除过树组件自身的构造需求,业务处理上往往需要这两个属性,而后端树工具要构造树结构,那一定是需要数据ID与父ID的。
如果感觉上面说的麻烦你就记住一点,不管是列表结构还是树形结构,始终保留数据ID与父ID两个属性就对了。
到这里又有一个新问题了,上面说了列表形式无需封装什么可以直接使用,既然如此那用列表形式的结构就完了呗,为什么写个工具类搞个树结构出来呢 ?
原因是,前端树组件的实现方式非常多,不同树插件或组件需要的数据格式可能不一样,有的列表、树形格式都支持,有的仅支持列表或树形的一种,所以为了满足不同前端树的展示需求,提供树形结构的构造工具是必要的。
3、话不多说,先实现个初版
从上面的内容我们了解了前端树组件的渲染展现需要后端提供满足需求的数据格式,那么实际上也就决定了树工具类的核心职责就是将一般的数据列表结构转换为树形结构,从而提供给前端使用。
解读上面所述的核心职责,首先一般列表是什么列表,此处我们假设为菜单列表,这就有了第一个类MenuEntity,紧接着是转换,谁转换成谁 ?数据列表转换树结构,树结构本身那应该就是个类,我们暂且叫它 TreeNode,结合我们第一步假设的菜单列表,那实际上就是 List< MenuEntity > 转换为 List < TreeNode > ,如此就得到了第二个类TreeNode,最后还剩转换这个动作谁去做 ? 那就是我们今天的主角 TreeUtil 了。
好,至此,通过分析树工具类的核心职责,我们分析得到了三个类。
-
MenuEntity
-
TreeNode
-
TreeUtil
OK,有了上面的内容那就来个简单的实现。
树节点类
public class TreeNode {
// 树节点ID
private String id;
// 树节点名称
private String name;
// 树节点编码
private String code;
// 树节点链接
private String linkUrl;
// 树节点图标
private String icon;
// 父节点ID
private String parentId;
}
菜单类
public class MenuEntity {
// 菜单ID
private String id;
// 上级菜单ID
private String pid;
// 菜单名称
private String name;
// 菜单编码
private String code;
// 菜单图标
private String icon;
// 菜单链接
private String url;
}
树工具类
public class TreeUtil {
/**
* 树构