zoukankan      html  css  js  c++  java
  • 在javascript中以数组链表法实现下拉树(原创)

        完整示例下载(树的实现过程已经封装成了一个类,方便有需要的人使用)

      在网页开发中,大部分的下拉菜单都是一行一项并且上下对齐,这样虽然很好但是缺乏层次结构感,客户不知道各个选项之间的关系,因此有的时候我们需要在下拉菜单中以树形结构展示下拉项,给客户更好的体验。比如:假设数据库中有张表存放了中国省市信息,如下所示:

     

        

    这张表是符合树形结构特征的,它的树形结构如右图所示,相信很多表都有这样的特征,这种结构的表以下拉树展示最好不过了,用户可以直接看出选项之间的关系。

          javascript实现树形结构应该有很多种方法,我也不知道那些方法都是如何实现的,也不想从网上下载现成的,因此决定自己写一个,刚开始没什么头绪,后来突然灵光一现,想到了数组链表的方法,大概思路如下,先上图:

      

      上面这幅图是树形结构在数组中的保存形式,每个节点以对象的形式存放在数组中,每个对象都有一个“array”属性,它是一个数组,指向它的所有子节点,"array"非常重要,树形结构的所有操作都要用到它,特别是对树的遍历,可以说是这个属性使多个数组组合起来形成一棵树,只不过这棵树是在内存中是无形的,我把它理解为“抽象树(我只是瞎说啊,仅是个人叫法,没有任何根据)”,是不是有点数组链表的味道啊?为了把它变为有形的树,我们可以对它进行遍历,在遍历的时候生成适当的html标签,最后生成树的完整html代码。

      下面介绍一下实现过程:

      首先,把数据库中的表以对象的形式保存在数组里面,怎么保存我就不说了,不是本文重点,为了简单我直接定义好一个数组,代码如下:

    //为了方便处理,表中每一行的信息以对象的形式存放在数组中
    var
    array = [ {id: 0,parentId: -1,name: "China" },{id: 1, parentId:0,name: "HeNan"},{id: 2, parentId:1, name:"LuoYang"}, {id: 3,parentId: 1,name: "ZhengZhou" },{id: 4,parentId: 0,name: "HeBei" },{id: 5,parentId: 4,name: "TangShang" }, {id: 6,parentId: 4,name: "ShiJiangZhuang" },{id: 7,parentId: 0,name: "HeiLongJiang" },{id: 8,parentId: 7,name: "Haerbin" }, {id: 9,parentId: 7,name: "DaQing" },{id: 10,parentId: 0,name: "GuangDong" },{id: 11,parentId: 10,name: "GuangZhou" }, {id: 12,parentId: 10,name: "FoShan" },{id:13,parentId:1,name:"KaiFeng"},{id:14, parentId: 2, name:"RuYang"}, {id:15,parentId:0,name:"meself"},{id:16,parentId:-1,name:"America"},{id:17,parentId:16,name:"Maiami"},
           {id:18,parentId:17,name:"Heat"} ];

       然后,对这个数组进行处理,给每个对象添加“level”属性,为了方便处理把数组按照对象的“level”属性从小到大进行排序,并给数组中每个对象添加最重要的"array”属性,然后遍历树生成树的html,代码如下:

    //给数组中的对象添加"level"属性
            this.initLevel = function(){
                    for(var i=0; i<this.array.length;i++)
                    {
                        this.level = 0;  //计算每个节点的层次之前,先重置为0
                        this.getLevel(this.array[i].id);
                        this.array[i].level = this.level;
                    }
                }
    
    //计算每个节点的层次
    this.getLevel = function (id)
            {
                if(!Boolean(this.array[id])||id==-1)
                {
                    //alert("The id "+ id +" is not included in array!");
                    return false;
                }
    
                if(this.array[id].id!=-1)
                {
                    this.level = this.level + 1;
                    //var iidd = this.array[id].parentId;
                    //arguments.callee(iidd);
                    this.getLevel(this.array[id].parentId);
                }
    
            }
    
    //初始化抽象树,处理根节点(支持多个根节点的情况,即:多棵树)
             this.initAbstructTree = function ()
             {
                 var rootCount = 0;
                 //array_1为全局变量
                 array_1 = new Array(1);
                 //shaobing = shaobing + 1;
                 for(var i=0;i<this.array.length;i++)
                 {
                     if(this.array[i].level==1)
                     {
                         rootCount++;
                         array_1[i] = this.array[i];
                         //shaobing = shaobing + 1;
                     }
                     else
                        break;
                 }
             }
    
            //创建抽象树,用递归的方式处理根结点以外的所有节点,以数组的形式建立树形结构
            this.createAbstructTree = function (arrayn)
            {
                //保存现在正在遍历array数组中的第几层
                var layer = arrayn[0].level + 1;
                if(layer>this.array[this.array.length-1].level)
                    return;
    
                for(var i=0;i<arrayn.length;i++)
                {
                      for(var j=0;j<this.array.length;j++)
                      {
                          if(this.array[j].level>layer)
                              break;
                          if(this.array[j].level == layer&&this.array[j].parentId == arrayn[i].id)
                          {
                              if(!Boolean(arrayn[i].array))
                              {
                                  arrayn[i].array = new Array();
                              }
                              arrayn[i].array.push(this.array[j]);
                          }
                      }
                      if(Boolean(arrayn[i].array))
                      {
                          this.createAbstructTree(arrayn[i].array);
                      }
    
                }
            }
    
    
            //按照数组中保存的抽象树形结构,递归生成树形结构的html
            this.generateTreeHtml = function (arrayn,signalArray)
            {
                for(var i=0;i<arrayn.length;i++)
                {
                    if(arrayn[i].level == 1)   //根节点
                    {
                        if(i == (arrayn.length-1)) //第一层的最后一个节点的图标不一样
                        {
                            this.html += "<div><div id='level"+arrayn[i].level+"_"+arrayn[i].id+"'><img src=\"images/Lminus.png\"><img src=\"images/openfoldericon.png\"><span>"+arrayn[i].name+"</span></div>";
                        }
                        else
                            this.html += "<div><div id='level"+arrayn[i].level+"_"+arrayn[i].id+"'><img src=\"images/Tminus.png\"><img src=\"images/openfoldericon.png\"><span>"+arrayn[i].name+"</span></div>";
    
                        //控制标签的显示,如果有子节点,则将所有的子节点放在<div>标签里面
                        if(Boolean(arrayn[i].array))
                        {
                            this.html += "<div>"
                        }
    
                        if(i == (arrayn.length-1))
                        {
                            if(Boolean(arrayn[i].array))  //有子节点
                            {
                                signalArray.push("blank");
                                this.generateTreeHtml(arrayn[i].array,signalArray);
                                signalArray.pop();
                            }
    
                        }
                        else
                        {
                            if(Boolean(arrayn[i].array))  //有子节点
                            {
                                signalArray.push("I");
                                this.generateTreeHtml(arrayn[i].array,signalArray);
                                signalArray.pop();
                            }
    
                        }
    
                        if(Boolean(arrayn[i].array))
                        {
                            this.html += "</div></div>"; //结束标签
                        }
                        else
                            this.html += "</div>"; //结束标签
                    }
                    else    //非根节点
                    {
                        //添加对应的外层图片
                        var outerbiaoqian="";
                        var innerbiaoqian="";
                        if(signalArray.length>0)
                        {
    
                            for(var k=0; k<signalArray.length;k++)
                            {
                                outerbiaoqian += "<img src='images/"+signalArray[k]+".png'>"
                            }
                        }
    
                        //添加自己的图片
                        if(i == arrayn.length-1) //最后一个节点
                        {
                            if(Boolean(arrayn[i].array))
                            {
                                //并且有子节点
                                innerbiaoqian+="<img src='images/Lminus.png'><img src='images/openfoldericon.png'>";
                                //signalArray.push("blank");
                            }
                            else
                            {
                                //没有子节点
                                innerbiaoqian+="<img src='images/L.png'>";
                                //signalArray.push("blank");
                            }
    
                        }
                        else  //不是最后一个节点
                        {
                            if(Boolean(arrayn[i].array))
                            {
                                //并且有子节点
                                innerbiaoqian+="<img src='images/Tminus.png'><img src='images/openfoldericon.png'>";
                            }
                            else
                            {
                                //没有子节点
                                innerbiaoqian+="<img src='images/T.png'>";
                            }
    
                        }
    
    
                        if(Boolean(arrayn[i].array))  //有子节点
                        {
                            this.html += "<div id='level"+arrayn[i].level+"_"+arrayn[i].id+"'>"+outerbiaoqian+innerbiaoqian+"<span>"+arrayn[i].name+"</span></div><div>";
                            if(i == arrayn.length-1) //最后一个节点
                            {
                                signalArray.push("blank");
                            }
                            else
                                signalArray.push("I");
                            this.generateTreeHtml(arrayn[i].array,signalArray);
                            signalArray.pop();
                            this.html += "</div>";
                        }
                        else   //没有子节点
                            this.html += "<div id='level"+arrayn[i].level+"_"+arrayn[i].id+"'>"+outerbiaoqian+innerbiaoqian+"<span>"+arrayn[i].name+"</span></div>";
    
                    }
                }
            }
    
    //调用此方法创建树形结构,在这个方法里依次调用上面的方法完成树的创建
            this.createTree = function ()
            {
                //this.array = array;
                this.initLevel(); //add property named level to all the object
                this.array.sort(this.compare("level")); //sort the array according to the object's property of level
                this.initAbstructTree();
                this.createAbstructTree(array_1); //执行完这个方法后,数组array_1就保存了树形结构的信息,即:array_1是抽象树的根
                this.generateTreeHtml(array_1,this.signalArray);
                $("#tree").html(this.html);
                this.success = true;
    
                tree_additionalFunction();
            }
    
        }
    
            
    //创建出树形结构以后,给树增加一些事件和样式
            function tree_additionalFunction()
            {
                //添加鼠标经过时的样式
                $("div[id^=level]").hover(function(){
                        $(this).addClass("dd");
                   },function(){
                        $(this).removeClass("dd");
                });
    
                //点击结点时获取结点的值,然后使树不可见
                $("div[id^=level]").click(function(){
    
                   $("#sele").val($(this).find("span").text());
                    //alert($(this).find("span").text());
                   $("#tree").slideUp();
                });
    
                //展开和收起结点时替换相应的图标
                $("div[id^=level]>img").click(function(){
                    if(this.nodeName == "IMG")
                    {
                        var temp = this.src.split('/');
                        var index = temp.length-1;
    
                        if(temp[index] == "Tminus.png" || temp[index] == "Lminus.png")
                        {
                            //左边的表达式先去掉路径中最后一个值,即:要被替换的图片名
                            temp.pop() == "Tminus.png"?this.src = temp.join('/')+"/Tplus.png":this.src = temp.join('/')+"/Lplus.png";
    
                            //替换文件夹图标
                            $(this).next().attr("src",temp.join('/')+"/foldericon.png");
    
                            $(this).parent().next().slideUp();
                            return false;
                        }
                        else if(temp[index] == "Tplus.png" || temp[index] == "Lplus.png")
                        {
                            //左边的表达式先去掉路径中最后一个值,即:要被替换的图片名
                            temp.pop() == "Tplus.png"?this.src = temp.join('/')+"/Tminus.png":this.src = temp.join('/')+"/Lminus.png";
    
                            //替换文件夹图标
                            $(this).next().attr("src",temp.join('/')+"/openfoldericon.png");
    
                            $(this).parent().next().slideDown();
                            return false;
                        }
                    }
                }

    生成树的html后,当点击下拉菜单时,显示在下面,就是下拉树了。下面提供一张运行截图:

    本人代码写的比较烂,本文的目的是提供一种思路。

     

  • 相关阅读:
    nacos 配置优先级
    spring cloud 依赖查询
    树-数据结构
    CI/CD + docker 综合实战
    CICD:CentOS 下 Jenkins 安装
    生产环境 OOM 与 GC 问题的处理思路
    如何优雅的进行接口管理
    合并多个Execl 电子表格 java poi
    深入了解数据导入的一些解决方案
    浅谈导出Execl的报表数据解决方案
  • 原文地址:https://www.cnblogs.com/neverstop/p/2475438.html
Copyright © 2011-2022 走看看