在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后,當點擊下拉菜單時,顯示在下面,就是下拉樹了。下面提供一張運行截圖:

本人代碼寫的比較爛,本文的目的是提供一種思路。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM