在javascript中以数组链表法实现下拉树

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

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

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

<img width="" height="" " src="http://img.ddvip.com/2014/0819/201408190841349030.jpg" />

上面这幅图是树形结构在数组中的保存形式,每个节点以对象的形式存放在数组中,每个对象都有一个“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);
            }

        }

//初始化抽象树,处理根节点(支持多个根节点的情况,即:多棵树)
//查看本栏目更多精彩内容:http://www.bianceng.cnhttp://www.bianceng.cn/webkf/script/
         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;
                    }
                }
            }

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索javascript
, 数组
, 结构
, 方法
, 下拉框 树形结构选择
, 树形
, 下拉
, JavaScript链表
, 下拉树
, 链地址法
, 下拉列表树
, 下拉树形框
, javascript树形菜单
javascript树形结构
数组实现链表、数组链表的实现、用数组实现链表、javascript 链表、c 链表实现,以便于您获取更多的相关知识。

时间: 2024-08-28 12:43:33

在javascript中以数组链表法实现下拉树的相关文章

javascript中Array数组的迭代方法实例分析

这篇文章主要介绍了javascript中Array数组的迭代方法,实例分析了Array数组的迭代方法定义与使用技巧,需要的朋友可以参考下 本文实例讲述了javascript迭代的方法.分享给大家供大家参考.具体实现方法如下: 代码如下: //filter() 利用指定的函数确定是否返回数组中包涵的某一项 var num = [1,2,3,4,5,6,12]; num.filter(function(item, index, array){ return (item > 2); //[3, 4,

javascript中的数组,对象的使用

问题描述 javascript中的数组,对象的使用 定义一个数组,如何编写代码便利里面的数据,结合dom对象里面的事件使网页导航栏有下级栏目 解决方案 JavaScript对象和数组JavaScript对象和数组JavaScript - Array对象的使用 及 数组排序 sort 解决方案二: js的数组使用教程:http://www.w3school.com.cn/js/js_obj_array.asp js的对象使用教程:http://www.w3school.com.cn/js/js_o

javascript中去除数组重复元素的实现方法【实例】_javascript技巧

在实际应用中,我们很多时候都可能需要去除数组中的重复元素,下面就是javascript数组去重的方法实现: <script language="javascript"> <!-- /*判断数组中是否存在某个元素的方法*/ function isExistInArr(_array, _element){ if(!_array || !_element) return false; if(!_array.length){ return (_array == _elemen

JavaScript中清空数组的方法总结_javascript技巧

 方式1,splice var ary = [1,2,3,4]; ary.splice(0,ary.length); console.log(ary); // 输出 [],空数组,即被清空了 方式2,length赋值为0 这种方式很有意思,其它语言如Java,其数组的length是只读的,不能被赋值.如 int[] ary = {1,2,3,4}; ary.length = 0; Java中会报错,编译通不过.而JS中则可以,且将数组清空了, var ary = [1,2,3,4]; ary.l

javascript中Array()数组函数详解_javascript技巧

在程序语言中数组的重要性不言而喻,JavaScript中数组也是最常使用的对象之一,数组是值的有序集合,由于弱类型的原因,JavaScript中数组十分灵活.强大,不像是Java等强类型高级语言数组只能存放同一类型或其子类型元素,JavaScript在同一个数组中可以存放多种类型的元素,而且是长度也是可以动态调整的,可以随着数据增加或减少自动对数组长度做更改. Array()是一个用来构建数组的内建构造器函数.数组主要由如下三种创建方式: array = new Array() array =

JavaScript中的数组遍历forEach()与map()方法以及兼容写法介绍_javascript技巧

•原理: •高级浏览器支持forEach方法 语法:forEach和map都支持2个参数:一个是回调函数(item,index,list)和上下文: •forEach:用来遍历数组中的每一项:这个方法执行是没有返回值的,对原来数组也没有影响: •数组中有几项,那么传递进去的匿名回调函数就需要执行几次: •每一次执行匿名函数的时候,还给其传递了三个参数值:数组中的当前项item,当前项的索引index,原始数组input: •理论上这个方法是没有返回值的,仅仅是遍历数组中的每一项,不对原来数组进行

JavaScript中的数组特性介绍_javascript技巧

与Java语言不同,JavaScript中的数组拥有三个特性:   1.无类型.数组的成员可以是任何类型,同一个数组也可以由很多不同类型的成员所组成. 2.长度可变.数组的长度是可以动态变化的,因此在JavaScript中不存在数组访问的越界问题. 3.不连续性.数组中成员的位置可以是连续的(0, 1, 2, 3-),也可以是不连续的.任何数组都有一个名为length的属性,在数组成员连续的情况下,length值与数组成员数目一致:当数组成员不连续时,length值要大于数组成员的数目.与连续的

js调用cs后台的c数组,怎样根据下拉框的值指定c数组下标?

问题描述 js调用cs后台的c数组,怎样根据下拉框的值指定c数组下标?//aspx:<selectid="AreaList"onChange="a()"runat="Server"><optionvalue="1">ah</option><optionvalue="2">vv</option></select><divid=&qu

原生JavaScript实现动态省市县三级联动下拉框菜单实例代码_javascript技巧

像平时购物选择地址时一样,通过选择的省动态加载城市列表,通过选择的城市动态加载县区列表,从而可以实现省市县的三级联动,下面使用原生的JavaScript来实现这个功能: 先给大家展示下测试结果: 未做任何选择时: 选择时: 代码如下所示: <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title>三级联动测试</titl