多叉樹結(jié)合JavaScript樹形控件實(shí)現(xiàn)無(wú)限級(jí)樹形菜單一種構(gòu)建多級(jí)有序樹形結(jié)構(gòu)JSON或XML數(shù)據(jù)源的方法_第1頁(yè)
多叉樹結(jié)合JavaScript樹形控件實(shí)現(xiàn)無(wú)限級(jí)樹形菜單一種構(gòu)建多級(jí)有序樹形結(jié)構(gòu)JSON或XML數(shù)據(jù)源的方法_第2頁(yè)
多叉樹結(jié)合JavaScript樹形控件實(shí)現(xiàn)無(wú)限級(jí)樹形菜單一種構(gòu)建多級(jí)有序樹形結(jié)構(gòu)JSON或XML數(shù)據(jù)源的方法_第3頁(yè)
多叉樹結(jié)合JavaScript樹形控件實(shí)現(xiàn)無(wú)限級(jí)樹形菜單一種構(gòu)建多級(jí)有序樹形結(jié)構(gòu)JSON或XML數(shù)據(jù)源的方法_第4頁(yè)
多叉樹結(jié)合JavaScript樹形控件實(shí)現(xiàn)無(wú)限級(jí)樹形菜單一種構(gòu)建多級(jí)有序樹形結(jié)構(gòu)JSON或XML數(shù)據(jù)源的方法_第5頁(yè)
已閱讀5頁(yè),還剩7頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

-.z多叉樹結(jié)合JavaScript樹形控件實(shí)現(xiàn)無(wú)限級(jí)樹形菜單〔一種構(gòu)建多級(jí)有序樹形構(gòu)造JSON〔或*ML〕數(shù)據(jù)源的方法〕一、問(wèn)題研究的背景和意義在Web應(yīng)用程序開發(fā)領(lǐng)域,基于AJA*技術(shù)的JavaScript樹形控件已經(jīng)被廣泛使用,它用來(lái)在Html頁(yè)面上展現(xiàn)具有層次構(gòu)造的數(shù)據(jù)項(xiàng)。目前市場(chǎng)上常見的JavaScript框架及組件庫(kù)中均包含自己的樹形控件,例如JQuery、Dojo、UI、E*tJS等,還有一些獨(dú)立的樹形控件,例如dhtml*tree等,這些樹形控件完美的解決了層次數(shù)據(jù)的展示問(wèn)題。展示離不開數(shù)據(jù),樹形控件主要利用AJA*技術(shù)從效勞器端獲取數(shù)據(jù)源,數(shù)據(jù)源的格式主要包括JSON、*ML等,而這些層次數(shù)據(jù)一般都存儲(chǔ)在數(shù)據(jù)庫(kù)中。“無(wú)限級(jí)樹形菜單〞,顧名思義,沒(méi)有級(jí)別的限制,它的數(shù)據(jù)通常來(lái)自數(shù)據(jù)庫(kù)中的無(wú)限級(jí)層次數(shù)據(jù),這種數(shù)據(jù)的存儲(chǔ)表通常包括id和parentId這兩個(gè)字段,以此來(lái)表示數(shù)據(jù)之間的層次關(guān)系?,F(xiàn)在問(wèn)題來(lái)了,既然樹形控件的數(shù)據(jù)源采用JSON或*ML等格式的字符串來(lái)組織層次數(shù)據(jù),而層次數(shù)據(jù)又存儲(chǔ)在數(shù)據(jù)庫(kù)的表中,則如何建立起樹形控件與層次數(shù)據(jù)之間的關(guān)系,換句話說(shuō),如何將數(shù)據(jù)庫(kù)中的層次數(shù)據(jù)轉(zhuǎn)換成對(duì)應(yīng)的層次構(gòu)造的JSON或*ML格式的字符串,返回給客戶端的JavaScript樹形控件.這就是我們要解決的關(guān)鍵技術(shù)問(wèn)題。本文將以目前市場(chǎng)上比較熾熱的E*tJS框架為例,講述實(shí)現(xiàn)無(wú)限級(jí)樹形菜單的方法,該方法同樣適用于其它類似的JS樹形控件。E*tJS框架是富客戶端開發(fā)中出類拔萃的框架之一。在E*t的UI控件中,樹形控件無(wú)疑是最為常用的控件之一,它用來(lái)實(shí)現(xiàn)樹形構(gòu)造的菜單。TreeNode用來(lái)實(shí)現(xiàn)靜態(tài)的樹形菜單,AsyncTreeNode用來(lái)實(shí)現(xiàn)動(dòng)態(tài)的異步加載樹形菜單,后者最為常用,它通過(guò)接收效勞器端返回來(lái)的JSON格式的數(shù)據(jù),動(dòng)態(tài)生成樹形菜單節(jié)點(diǎn)。動(dòng)態(tài)生成樹有兩種思路:一種是一次性生成全部樹節(jié)點(diǎn),另一種是逐級(jí)加載樹節(jié)點(diǎn)〔利用AJA*,每次點(diǎn)擊節(jié)點(diǎn)時(shí)查詢下一級(jí)節(jié)點(diǎn)〕。對(duì)于大數(shù)據(jù)量的菜單節(jié)點(diǎn)來(lái)說(shuō),逐級(jí)加載是比較適宜的選擇,但是對(duì)于小數(shù)據(jù)量的菜單來(lái)說(shuō),一次性生成全部節(jié)點(diǎn)應(yīng)該是最為合理的方案。在實(shí)際應(yīng)用開發(fā)中,一般不會(huì)遇到特別大數(shù)據(jù)量的場(chǎng)景,所以一次性生成全部菜單節(jié)點(diǎn)是我們重點(diǎn)研究的技術(shù)點(diǎn),也就是本文要解決的關(guān)鍵技術(shù)問(wèn)題。本文以基于E*tJS的應(yīng)用系統(tǒng)為例,講述如何將數(shù)據(jù)庫(kù)中的無(wú)限級(jí)層次數(shù)據(jù)一次性在界面中生成全部菜單節(jié)點(diǎn)〔例如在界面中以樹形方式一次性展示出銀行所有分支機(jī)構(gòu)的信息〕,同時(shí)對(duì)每一個(gè)層次的菜單節(jié)點(diǎn)按照*一屬性和規(guī)則排序,展示出有序的菜單樹。解決一次性構(gòu)造無(wú)限級(jí)樹形菜單的問(wèn)題,可以拓展出更多的應(yīng)用場(chǎng)景,例如樹形構(gòu)造表格TreeGrid,一次性生成樹形表格,對(duì)樹形表格進(jìn)展完整分頁(yè),對(duì)表格列進(jìn)展全排序;或者可以利用本文的思路擴(kuò)展出其他的更復(fù)雜的應(yīng)用場(chǎng)景。先看兩個(gè)圖例,有個(gè)直觀上的認(rèn)識(shí):圖一,銀行分支機(jī)構(gòu)樹形構(gòu)造菜單圖二,樹形構(gòu)造表格二、詳細(xì)設(shè)計(jì)方案讓我們先看兩段代碼片段:文件一,branchTree.html〔E*t樹形控件頁(yè)面〕E*t.onReady( function(){ vartree=newE*t.tree.TreePanel({height:300,width:400,animate:true,enableDD:true,containerScroll:true,rootVisible:false,frame:true,//getBranch.do請(qǐng)求效勞器返回多級(jí)樹形構(gòu)造的JSON字符串loader:newE*t.tree.TreeLoader({dataUrl:'getBranch.do'}),root:newE*t.tree.AsyncTreeNode({id:'0',te*t:'根結(jié)點(diǎn)'})});tree.e*pandAll();});文件二,branchTreeJSON.jsp〔接收getBranch.do請(qǐng)求,返回多級(jí)樹形構(gòu)造的JSON字符串〕<%//讀取銀行分支機(jī)構(gòu)的層次數(shù)據(jù)Listresult=DataAccess.getBankInfoList();//將層次數(shù)據(jù)轉(zhuǎn)換為多叉樹對(duì)象〔本文下面會(huì)詳細(xì)介紹該數(shù)據(jù)構(gòu)造的實(shí)現(xiàn)方法〕Noderoot=E*tTreeHelper.createE*tTree(result);%>[<%=root.toString()%><!--以JSON的形式返回響應(yīng)數(shù)據(jù),E*t.tree.TreeLoader會(huì)根據(jù)此數(shù)據(jù)生成樹形菜單-->]以上兩個(gè)程序文件是一次性生成無(wú)限級(jí)樹形菜單所必須的,其中最為關(guān)鍵的局部就是如何生成一個(gè)無(wú)限級(jí)的樹形構(gòu)造JSON字符串,返回給客戶端的E*t樹形控件。對(duì)于銀行分支機(jī)構(gòu)來(lái)說(shuō),需要返回類似如下的JSON串:{ id:'100000', te*t:'**銀行總行', children:[ { id:'110000', te*t:'**分行', children:[ { id:'113000', te*t:'**銀行開發(fā)區(qū)支行', leaf:true },{ id:'112000', te*t:'**銀行解放道支行', children:[ { id:'112200', te*t:'**銀行三大街支行', leaf:true }, { id:'112100', te*t:'**銀行廣陽(yáng)道支行', leaf:true } ] }, { id:'111000', te*t:'**銀行金光道支行', leaf:true } ] } ]}同時(shí)還需要對(duì)樹中每一個(gè)層次的節(jié)點(diǎn)按照*一屬性〔比方分支機(jī)構(gòu)編號(hào)〕進(jìn)展排序,以展示出有序的樹形菜單?,F(xiàn)在可以把問(wèn)題概括為:把數(shù)據(jù)庫(kù)中的層次數(shù)據(jù)轉(zhuǎn)換成多級(jí)樹形構(gòu)造的JSON格式的字符串對(duì)樹中每一個(gè)層次的節(jié)點(diǎn)按照*一屬性〔比方分支機(jī)構(gòu)編號(hào)〕進(jìn)展排序下面介紹解決問(wèn)題的思路:在數(shù)據(jù)構(gòu)造這門課中,我們都學(xué)過(guò)樹,無(wú)限級(jí)樹形菜單就可以抽象成一種多叉樹構(gòu)造,即每個(gè)節(jié)點(diǎn)下包含多個(gè)子節(jié)點(diǎn)的樹形構(gòu)造,首先就需要把數(shù)據(jù)庫(kù)中的層次數(shù)據(jù)轉(zhuǎn)換成多叉樹構(gòu)造的對(duì)象樹,也就是構(gòu)造出一棵多叉樹。有了數(shù)據(jù)構(gòu)造,還要實(shí)現(xiàn)相應(yīng)的算法,我們需要實(shí)現(xiàn)兩種算法:1、兄弟節(jié)點(diǎn)橫向排序算法,對(duì)隸屬于同一個(gè)父節(jié)點(diǎn)下面的所有直接子節(jié)點(diǎn)按照*一節(jié)點(diǎn)屬性和規(guī)則進(jìn)展排序,保持兄弟節(jié)點(diǎn)橫向有序;2、先序遍歷算法,遞歸打印出無(wú)限級(jí)JSON字符串。概括起來(lái)分為三步:構(gòu)造無(wú)序的多叉樹構(gòu)造實(shí)現(xiàn)兄弟節(jié)點(diǎn)橫向排序方法實(shí)現(xiàn)先序遍歷方法,打印出JSON字符串如下列圖:我們給這棵樹起個(gè)名字吧,就叫做multipletree

,簡(jiǎn)稱M-Tree。三、源代碼實(shí)現(xiàn)〔Java語(yǔ)言版〕實(shí)現(xiàn)這樣一顆樹,需要設(shè)計(jì)三個(gè)類:樹類〔MultipleTree.java〕、節(jié)點(diǎn)類〔Node.java〕、孩子列表類〔Children.java〕;為了方便演示,還需要構(gòu)造一些假的層次數(shù)據(jù),因此還需要建一個(gè)構(gòu)造假數(shù)據(jù)的類〔VirtualDataGenerator.java〕,以下代碼拷貝出來(lái)之后可直接運(yùn)行測(cè)試:packagetest;importjava.util.ArrayList;importjava.util.parator;importjava.util.HashMap;importjava.util.Iterator;importjava.util.List;importjava.util.Map;importjava.util.Set;importjava.util.Collections;/***多叉樹類*/publicclassMultipleTree{ publicstaticvoidmain(String[]args){ //讀取層次數(shù)據(jù)結(jié)果集列表 ListdataList=VirtualDataGenerator.getVirtualResult(); //節(jié)點(diǎn)列表〔散列表,用于臨時(shí)存儲(chǔ)節(jié)點(diǎn)對(duì)象〕 HashMapnodeList=newHashMap(); //根節(jié)點(diǎn) Noderoot=null; //根據(jù)結(jié)果集構(gòu)造節(jié)點(diǎn)列表〔存入散列表〕 for(Iteratorit=dataList.iterator();it.hasNe*t();){ MapdataRecord=(Map)it.ne*t(); Nodenode=newNode(); node.id=(String)dataRecord.get("id"); node.te*t=(String)dataRecord.get("te*t"); node.parentId=(String)dataRecord.get("parentId"); nodeList.put(node.id,node); } //構(gòu)造無(wú)序的多叉樹 SetentrySet=nodeList.entrySet(); for(Iteratorit=entrySet.iterator();it.hasNe*t();){ Nodenode=(Node)((Map.Entry)it.ne*t()).getValue(); if(node.parentId==null||node.parentId.equals(")){ root=node; }else{ ((Node)nodeList.get(node.parentId)).addChild(node); } } //輸出無(wú)序的樹形菜單的JSON字符串 System.out.println(root.toString()); //對(duì)多叉樹進(jìn)展橫向排序 root.sortChildren(); //輸出有序的樹形菜單的JSON字符串 System.out.println(root.toString()); //程序輸出結(jié)果如下〔無(wú)序的樹形菜單〕〔格式化后的結(jié)果〕: // { // id:'100000', // te*t:'**銀行總行', // children:[ // { // id:'110000', // te*t:'**分行', // children:[ // { // id:'113000', // te*t:'**銀行開發(fā)區(qū)支行', // leaf:true // }, // { // id:'111000', // te*t:'**銀行金光道支行', // leaf:true // }, // { // id:'112000', // te*t:'**銀行解放道支行', // children:[ // { // id:'112200', // te*t:'**銀行三大街支行', // leaf:true // }, // { // id:'112100', // te*t:'**銀行廣陽(yáng)道支行', // leaf:true // } // ] // } // ] // } // ] // } //程序輸出結(jié)果如下〔有序的樹形菜單〕〔格式化后的結(jié)果〕: // {// id:'100000', // te*t:'**銀行總行', // children:[ // { // id:'110000', // te*t:'**分行', // children:[ // { // id:'111000', // te*t:'**銀行金光道支行', // leaf:true // }, // { // id:'112000', // te*t:'**銀行解放道支行', // children:[ // { // id:'112100', // te*t:'**銀行廣陽(yáng)道支行', // leaf:true // }, // { // id:'112200', // te*t:'**銀行三大街支行', // leaf:true // } // ] // }, // { // id:'113000', // te*t:'**銀行開發(fā)區(qū)支行', // leaf:true // } // ] // } // ] // } }}/***節(jié)點(diǎn)類*/classNode{ /** *節(jié)點(diǎn)編號(hào) */ publicStringid; /** *節(jié)點(diǎn)內(nèi)容 */ publicStringte*t; /** *父節(jié)點(diǎn)編號(hào) */ publicStringparentId; /** *孩子節(jié)點(diǎn)列表 */ privateChildrenchildren=newChildren(); //先序遍歷,拼接JSON字符串 publicStringtoString(){ Stringresult="{" +"id:'"+id+"'" +",te*t:'"+te*t+"'"; if(children!=null&&children.getSize()!=0){ result+=",children:"+children.toString(); }else{ result+=",leaf:true"; } returnresult+"}"; } //兄弟節(jié)點(diǎn)橫向排序 publicvoidsortChildren(){ if(children!=null&&children.getSize()!=0){ children.sortChildren(); } } //添加孩子節(jié)點(diǎn) publicvoidaddChild(Nodenode){ this.children.addChild(node); }}/***孩子列表類*/classChildren{ privateListlist=newArrayList(); publicintgetSize(){ returnlist.size(); } publicvoidaddChild(Nodenode){ list.add(node); } //拼接孩子節(jié)點(diǎn)的JSON字符串 publicStringtoString(){ Stringresult="["; for(Iteratorit=list.iterator();it.hasNe*t();){ result+=((Node)it.ne*t()).toString(); result+=","; } result=result.substring(0,result.length()-1); result+="]"; returnresult; } //孩子節(jié)點(diǎn)排序 publicvoidsortChildren(){ //對(duì)本層節(jié)點(diǎn)進(jìn)展排序 //可根據(jù)不同的排序?qū)傩?,傳入不同的比較器,這里傳入ID比較器 Collections.sort(list,newNodeIDparator()); //對(duì)每個(gè)節(jié)點(diǎn)的下一層節(jié)點(diǎn)進(jìn)展排序 for(Iteratorit=list.iterator();it.hasNe*t();){ ((Node)it.ne*t()).sortChildren(); } }}/***節(jié)點(diǎn)比較器*/classNodeIDparatorimplementsparator{ //按照節(jié)點(diǎn)編號(hào)比較 publicintpare(Objecto1,Objecto2){intj1=Integer.parseInt(((Node)o1).id); intj2=Integer.parseInt(((Node)o2).id);return(j1<j2?-1:(j1==j2?0:1)); } }/***構(gòu)造虛擬的層次數(shù)據(jù)*/classVirtualDataGenerator{ //構(gòu)造無(wú)序的結(jié)果集列表,實(shí)際應(yīng)用中,該數(shù)據(jù)應(yīng)該從數(shù)據(jù)庫(kù)中查詢獲得; publicstaticListgetVirtualResult(){ ListdataList=newArrayList(); HashMapdataRecord1=newHashMap(); dataRecord1.put("id","112000"); dataRecord1.put("te*t","**銀行解放道支行"); dataRecord1.put("parentId","110000"); HashMapdataRecord2=newHashMap(); dataRecord2.put("id","112200"); dataRecord2.put("te*t","**銀行三大街支行"); dataRecord2.put("parentId","112000"); HashMapdataRecord3=newHashMap(); dataRecord3.put("id","112100"); dataRecord3.put("te*t","**銀行廣陽(yáng)道支行"); dataRecord3.put("parentId","112000"); HashMapdataRecord4=newHashMap(); dataRecord4.put("id","113000"); dataRecord4.put("te*t","**銀行開發(fā)區(qū)支行"); dataRecord4.put("parentId","110000"); HashMapdataRecord5=newHashMap(); dataRecord5.put("id","100000"); dataRecord5.put("te*t","**銀行總行"); dataRecord5.put("parentId","); HashMapdataRecord6=newHashMap(); dataRecord6.put("id","110000"); dataRecord6.put("te*t","**分行"); dataRecord6.put("parentId","100000"); HashMapdataRecord7=newHashMap(); dataRecord7.put("id","111000"); dataRecord7.put("te*t","**銀行金光道支行"); dataRecord7.put("parentId","110000"); dataList.add(dataRecord1); dataList.add(dataRecord2); dataList.add(dataRecord3); dataList.add(dataRecord4); dataList.add(dataRecord5); dataList.add(dataRecord6); dataList.add(dataRecord7); returndataList; } }好了,通過(guò)上面的代碼,就可以實(shí)現(xiàn)多叉樹的兄弟節(jié)點(diǎn)橫向排序和先序遍歷了,實(shí)現(xiàn)了將層次數(shù)據(jù)轉(zhuǎn)換為有序無(wú)限級(jí)樹形構(gòu)造JSON字符串的目的。在實(shí)際的工程中,可以把上面的有效代碼融入其中,或者在此根底上進(jìn)展一些擴(kuò)展:實(shí)現(xiàn)對(duì)指定層次的排序〔例如只排序第一層的節(jié)點(diǎn),或者只排序*一父節(jié)點(diǎn)下的所有子節(jié)點(diǎn)〕遍歷輸出樹形構(gòu)造時(shí)可以參加判斷條件過(guò)濾掉*些節(jié)點(diǎn)實(shí)現(xiàn)節(jié)點(diǎn)的刪除功能在節(jié)點(diǎn)類中增加一個(gè)父節(jié)點(diǎn)的引用,就可以計(jì)算出*一節(jié)點(diǎn)所處的級(jí)別在不支持層次查詢〔hieraricalretrival〕的數(shù)據(jù)庫(kù)應(yīng)用系統(tǒng)中使用該算法實(shí)現(xiàn)一樣的效果四、思考與總結(jié)這篇文章的重點(diǎn)是如何構(gòu)造有序的無(wú)限級(jí)的樹形構(gòu)造JSON字符串,一次性生成樹形菜單,而不是利用AJA*的方式,反復(fù)向效勞器端發(fā)送請(qǐng)求,一級(jí)接一級(jí)的加載樹節(jié)點(diǎn)。既然可以構(gòu)造無(wú)限級(jí)的JSON字符串,則也可以根據(jù)這個(gè)思路構(gòu)造無(wú)限級(jí)的*ML字符串,或者構(gòu)造具有層次構(gòu)造的UL–LI組合〔用UL-LI來(lái)展示樹形構(gòu)造〕,或者構(gòu)造具有層次構(gòu)造的TABLE〔用TABLE來(lái)展示樹形構(gòu)造〕。如下所示:〔1〕*ML層次構(gòu)造<menuGroupid="100000"name="**銀行總行"> <menuGroupid="110000"name="**分行"> <menuid="113000"name="**銀行開發(fā)區(qū)支行"> </menu> <menuid="111000"name="**銀行金光道支行"> </menu> <menuGroupid="112000"name="**銀行解放道支行"> <menuid="112200"name="**銀行三大街支行"> </menu> <menuid="112100"name="**銀行廣陽(yáng)道支行"> </menu> </menuGroup> </menuGroup></menuGroup>〔2〕UL-LI層次構(gòu)造<ul> <li>**銀行總行</li> <ul> <li>**分行<

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論