写代码不用递归构造树,可以吗?看看ztree插件怎么实现的吧

ztree是一个依靠 jQuery 库实现的多功能 “树插件”。其优异的性能、灵活的配置、多种功能的组合是 zTree 最大优点。这个插件我也一直在使用,真的特别的好,到现在中国各行各业好多Web系统中,都是用ztree去做树结构导航功能。使用简直是太容易了、太简单了。无可挑剔!

如果有了一定的编程能力,建议大家还是看下ztree的源码,不管是后端还是前端,它的源码也是值得我们参考学习的。比如本文说的树构造的问题,部分童鞋在写树机构的时候,可能会用递归算法去把一个数组结构的数据,根据一定的标识构造成树机构形式(即带有层级结构格式,例如文件夹层级)的数据,可能在工作或生活中,受到使用的开发语言和环境的影响,没有考虑过其他代码逻辑是否更好的构造树结构呢!

在某些通用的场景中,会有这种需求:我有很多种类型的数组机构的列表数据,里面包含了层级关系的标识,我只要提供每种数组数据里面标识的名字,即可自动统一的构造成树结构。

而ztree就是具有这种功能的一种插件。你只要提供类似于如下的数据结构:

var nodes = [
	{id:1, pId:0, name: "父节点1"},
	{id:11, pId:1, name: "子节点1"},
	{id:12, pId:1, name: "子节点2"}
];

他就会自动处理,变成如下的树结构:

var nodes = [{
   name: "父节点1", 
   id:1,
   children: [
			{id:11,name: "子节点1"},
			{id:12,name: "子节点2"}
	 ]}
];

那ztree是怎么做的,首先其提供了一个【setting.data.simpleData.enable】配置项,用于告诉ztree是否是简单格式的数据(即二维表格的数据数据),然后根据这个配置项,让我们找到其源码目录下的js文件夹下的jquery.ztree.core.js文件,搜索一下,大概在895行的位置上,有一段如下代码:

 if (setting.data.simpleData.enable) {
      newNodes = data.transformTozTreeFormat(setting, newNodes);
 }

这段代码的意图很明显了吧,如果这个参数配置项为真,就把现在结构的数据传递到transformTozTreeFormat这个方法中,并返回一个新结构,而这个新结构便是具有树结构的数据了。

接下来,在搜索一下这个方法,大概在661行左右,发现了这个方法,代码段如下,20行左右的代码量:

transformTozTreeFormat: function (setting, sNodes) {
    var i, l,
        key = setting.data.simpleData.idKey,
        parentKey = setting.data.simpleData.pIdKey,
        childKey = setting.data.key.children;
    if (!key || key == "" || !sNodes) return [];

    if (tools.isArray(sNodes)) {
        var r = [];
        var tmpMap = {};
        for (i = 0, l = sNodes.length; i < l; i++) {
            tmpMap[sNodes[i][key]] = sNodes[i];
        }
        for (i = 0, l = sNodes.length; i < l; i++) {
            if (tmpMap[sNodes[i][parentKey]] && sNodes[i][key] != sNodes[i][parentKey]) {
                if (!tmpMap[sNodes[i][parentKey]][childKey])
                    tmpMap[sNodes[i][parentKey]][childKey] = [];
                tmpMap[sNodes[i][parentKey]][childKey].push(sNodes[i]);
            } else {
                r.push(sNodes[i]);
            }
        }
        return r;
    } else {
        return [sNodes];
    }
}

让我们来解析一下这段代码:

1、首先读取了3行参数配置项,动态获取了id的名称是那个属性,父Id的名称是哪个属性,子集合是哪个属性;

2、然后判断是否为空数据、是否指定了id的属性,没有指定的话返回当前数组;

3、定义了2个属性:r、tmpMap,其中r用来存储新结构数据,tmpMap用于将每一行的数据进行一个映射绑定,相当于做了一个根据唯一标识ID快速从数组中查询某个对象的的操作,如果要取出ID等于15的数据,直接tmpMap["15"]即可。这步骤执行完成后,我们需要知道一件事:想获取最后那个最顶级的节点对应的数据对象,这里是获取不到的。

4、开始遍历数据,判断临时的那个tmpMap映射中是否有当前节点的父节点数据,并且当前节点的标识和父标识不相等:

如果条件成立,说明当前节点是那个父节点的儿子,那么在判断当前节点的父节点的儿子数组是否为空或者不存在,如果不存在,先初始化一个儿子的空数组,然后把当前节点,放到那个父节点的儿子数组里面,依次循环往复,如果当前节点的父节点在临时的tmpMap映射中不存在,说明了,这时的遍历的节点,就是是一个最顶级的节点了(有些时候根据提供的数据会是多个);

反之条件不成立,说明当前节点为顶级节点

5、返回新的树结构的数组。

我不知道以上我的这段解析是否可以让你明白,建议经验不足的开发者可以多思考一下。挺好的。

ztree这段代码,其实非常巧妙,20行简简单单的代码,不仅扩展了我们的思维方式,也提高了我们的开发能力,做某些功能开发时,也会联想到这种思想,并用这种思想解决一些实际的构造和遍历的问题。

例如我将一个二维结构的数据,通过Map方式换成一个类似于目录或索引的结构方式,可以快速的通过某个key去查询到某个对象数据,然后当在某些地方需要找某个ID的时候,就不需要再次进行遍历了。

ztree的这段代码,也利用了Javascript的方括号方式取值的语法,来获取指定的属性,同时这个这种语法,提高了动态性操作。

不知道这篇文章是否帮助到你了呢,如果有请点个赞,转个发。如果有什么想说的,可以评论,大家一起进行讨论下!

 

 

 

 

©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页