JavaScript樹形組件實(shí)現(xiàn)無限級(jí)樹形結(jié)構(gòu)
?一、問題研究的背景和意義?
在Web應(yīng)用程序開發(fā)領(lǐng)域,基于Ajax技術(shù)的JavaScript樹形組件已經(jīng)被廣泛使用,它用來在Html頁面上展現(xiàn)具有層次結(jié)構(gòu)的數(shù)據(jù)項(xiàng)。目前市場(chǎng)上常見的JavaScript框架及組件庫中均包含自己的樹形組件,例如jQuery、Ext JS等,還有一些獨(dú)立的樹形組件,例如dhtmlxTree
等,這些樹形組件完美的解決了層次數(shù)據(jù)的展示問題。展示離不開數(shù)據(jù),樹形組件主要利用Ajax技術(shù)從服務(wù)器端獲取數(shù)據(jù)源,數(shù)據(jù)源的格式主要包括JSON、XML等,而這些層次數(shù)據(jù)一般都存儲(chǔ)在數(shù)據(jù)庫中。“無限級(jí)樹形結(jié)構(gòu)”,顧名思義,沒有級(jí)別的限制,它的數(shù)據(jù)通常來自數(shù)據(jù)庫中的無限級(jí)層次數(shù)據(jù),這種數(shù)據(jù)的存儲(chǔ)表通常包括id和parentId這兩個(gè)字段,以此來表示數(shù)據(jù)之間的層次關(guān)系?,F(xiàn)在問題來了,既然樹形組件的數(shù)據(jù)源采用JSON或XML等格式的字符串來組織層次數(shù)據(jù),而層次數(shù)據(jù)又存儲(chǔ)在數(shù)據(jù)庫的表中,那么如何建立起樹形組件與層次數(shù)據(jù)之間的關(guān)系,換句話說,如何將數(shù)據(jù)庫中的層次數(shù)據(jù)轉(zhuǎn)換成對(duì)應(yīng)的層次結(jié)構(gòu)的JSON或XML格式的字符串,返回給客戶端的JavaScript樹形組件?這就是我們要解決的關(guān)鍵技術(shù)問題。本文將以目前市場(chǎng)上比較知名的Ext JS框架為例,講述實(shí)現(xiàn)無限級(jí)樹形結(jié)構(gòu)的方法,該方法同樣適用于其它類似的JavaScript樹形組件。
Ext JS框架是富客戶端開發(fā)中出類拔萃的框架之一。在Ext的UI組件中,樹形組件無疑是最為常用的組件之一,它用來實(shí)現(xiàn)樹形結(jié)構(gòu)的視圖。TreeNode用來實(shí)現(xiàn)靜態(tài)的樹形結(jié)構(gòu),AsyncTreeNode
用來實(shí)現(xiàn)動(dòng)態(tài)的異步加載樹形結(jié)構(gòu),后者最為常用,它通過接收服務(wù)器端返回來的JSON格式的數(shù)據(jù),動(dòng)態(tài)生成樹形結(jié)構(gòu)節(jié)點(diǎn)。動(dòng)態(tài)生成樹有兩種思路:一種是一次性生成全部樹節(jié)點(diǎn),另一種是逐級(jí)加載樹節(jié)點(diǎn)(利用Ajax,每次點(diǎn)擊節(jié)點(diǎn)時(shí)查詢下一級(jí)節(jié)點(diǎn))。對(duì)于大數(shù)據(jù)量的樹節(jié)點(diǎn)來說,逐級(jí)加載是比較合適的選擇,但是對(duì)于小數(shù)據(jù)量的樹節(jié)點(diǎn)來說,一次性生成全部節(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ù)問題。本文以基于Ext JS的應(yīng)用系統(tǒng)為例,講述如何將數(shù)據(jù)庫中的無限級(jí)層次數(shù)據(jù)一次性在界面中生成全部樹節(jié)點(diǎn)(例如在界面中以樹形方式一次性展示出銀行所有分支機(jī)構(gòu)的信息),同時(shí)對(duì)每一個(gè)層次的節(jié)點(diǎn)按照某一屬性和規(guī)則排序,展示出有序的樹形結(jié)構(gòu)。
解決一次性構(gòu)造無限級(jí)樹形結(jié)構(gòu)的問題,可以拓展出更多的應(yīng)用場(chǎng)景,例如樹形結(jié)構(gòu)表格TreeGrid,一次性生成樹形表格,對(duì)樹形表格進(jìn)行完整分頁,對(duì)表格列進(jìn)行全排序;或者可以利用本文的思路擴(kuò)展出其他的更復(fù)雜的應(yīng)用場(chǎng)景。
先看兩個(gè)圖例,有個(gè)直觀上的認(rèn)識(shí):
圖一,銀行分支機(jī)構(gòu)樹形結(jié)構(gòu):
圖二,樹形結(jié)構(gòu)表格:
?二、詳細(xì)設(shè)計(jì)方案?
讓我們先看兩段代碼片段:
文件一,branchTree.html (Ext樹形組件頁面)
Ext.onReady( function(){ ? ?var ?tree = new Ext.tree.TreePanel({ ? ? ? height: 300, ? ? ? width: 400, ? ? ? animate:true, ? ? ? enableDD:true, ? ? ? containerScroll: true, ? ? ? rootVisible: false, ? ? ? frame: true, ? ? ? // getBranch.do請(qǐng)求服務(wù)器返回多級(jí)樹形結(jié)構(gòu)的JSON字符串 ? ? ? ?loader: new Ext.tree.TreeLoader({dataUrl:'getBranch.do'}), ? ? ? ? root : new Ext.tree.AsyncTreeNode({id:'0',text:'根結(jié)點(diǎn)'}) ? ? ? ?}); ? ? ? ? ? ?tree.expandAll(); ?} );
文件二,branchTreeJSON.jsp (接收getBranch.do請(qǐng)求,返回多級(jí)樹形結(jié)構(gòu)的JSON字符串)
<% // 讀取銀行分支機(jī)構(gòu)的層次數(shù)據(jù) List result = DataAccess.getBankInfoList(); // 將層次數(shù)據(jù)轉(zhuǎn)換為多叉樹對(duì)象(本文下面會(huì)詳細(xì)介紹該數(shù)據(jù)結(jié)構(gòu)的實(shí)現(xiàn)方法) Node root = ExtTreeHelper.createExtTree(result); ? %> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? [ <%=root.toString()%> <!-- 以JSON的形式返回響應(yīng)數(shù)據(jù),Ext.tree.TreeLoader會(huì)根據(jù)此數(shù)據(jù)生成樹形結(jié)構(gòu) --> ]
以上兩個(gè)程序文件是一次性生成無限級(jí)樹形結(jié)構(gòu)所必須的,其中最為關(guān)鍵的部分就是如何生成一個(gè)無限級(jí)的樹形結(jié)構(gòu)JSON字符串,返回給客戶端的Ext樹形組件。
對(duì)于銀行分支機(jī)構(gòu)來說,需要返回類似如下的JSON串:
{ ?id: '100000', ?text: '廊坊銀行總行', ?children: [ ? ?{ ? ? ?id: '110000', ? ? ?text: '廊坊分行', ? ? ?children: [ ? ? ? ?{ ? ? ? ? ?id: '113000', ? ? ? ? ?text: '廊坊銀行開發(fā)區(qū)支行', ? ? ? ? ?leaf: true ? ? ? ?}, ? ? ? ?{ ? ? ? ? ?id: '112000', ? ? ? ? ?text: '廊坊銀行解放道支行', ? ? ? ? ?children: [ ? ? ? ? ? ?{ ? ? ? ? ? ? ?id: '112200', ? ? ? ? ? ? ?text: '廊坊銀行三大街支行', ? ? ? ? ? ? ?leaf: true ? ? ? ? ? ?}, ? ? ? ? ? ?{ ? ? ? ? ? ? ?id: '112100', ? ? ? ? ? ? ?text: '廊坊銀行廣陽道支行', ? ? ? ? ? ? ?leaf: true ? ? ? ? ? ?} ? ? ? ? ?] ? ? ? ?}, ? ? ? ?{ ? ? ? ? ?id: '111000', ? ? ? ? ?text: '廊坊銀行金光道支行', ? ? ? ? ?leaf: true ? ? ? ?} ? ? ?] ? ?} ?] }
同時(shí)還需要對(duì)樹中每一個(gè)層次的節(jié)點(diǎn)按照某一屬性(比如分支機(jī)構(gòu)編號(hào))進(jìn)行排序,以展示出有序的樹形結(jié)構(gòu)。
現(xiàn)在可以把問題概括為:
- 1、 把數(shù)據(jù)庫中的層次數(shù)據(jù)轉(zhuǎn)換成多級(jí)樹形結(jié)構(gòu)的JSON格式的字符串
- 2、 對(duì)樹中每一個(gè)層次的節(jié)點(diǎn)按照某一屬性(比如分支機(jī)構(gòu)編號(hào))進(jìn)行排序
下面介紹解決問題的思路:
在數(shù)據(jù)結(jié)構(gòu)這門課中,我們都學(xué)過樹,無限級(jí)樹形結(jié)構(gòu)就可以抽象成一種多叉樹結(jié)構(gòu),即每個(gè)節(jié)點(diǎn)下包含多個(gè)子節(jié)點(diǎn)的樹形結(jié)構(gòu),首先就需要把數(shù)據(jù)庫中的層次數(shù)據(jù)轉(zhuǎn)換成多叉樹結(jié)構(gòu)的對(duì)象樹,也就是構(gòu)造出一棵多叉樹。
有了數(shù)據(jù)結(jié)構(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、先序遍歷算法,遞歸打印出無限級(jí)JSON字符串。
概括起來分為三步:
- 1、 構(gòu)造無序的多叉樹結(jié)構(gòu)
- 2、 實(shí)現(xiàn)兄弟節(jié)點(diǎn)橫向排序方法
- 3、 實(shí)現(xiàn)先序遍歷方法,打印出JSON字符串
如圖所示:
?三、源代碼實(shí)現(xiàn)(Java版)?
實(shí)現(xiàn)這樣一顆樹,需要設(shè)計(jì)兩個(gè)類:樹類(MultipleTree)、節(jié)點(diǎn)類(Node);排序時(shí)還需要一個(gè)比較器類(NodeIDComparator);為了方便演示,還需要構(gòu)造一些假的層次數(shù)據(jù),因此還需要建一個(gè)構(gòu)造假數(shù)據(jù)的類(VirtualDataGenerator),以下代碼拷貝出來之后可直接運(yùn)行測(cè)試:
package test; import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Collections; /** * 多叉樹類 */ public class MultipleTree { public static void main(String[] args) { ? // 讀取層次數(shù)據(jù)結(jié)果集列表 ? ?List dataList = VirtualDataGenerator.getVirtualResult(); ?// 節(jié)點(diǎn)列表(映射表,用于臨時(shí)存儲(chǔ)節(jié)點(diǎn)對(duì)象) ?HashMap nodeList = new HashMap(); ?// 根節(jié)點(diǎn) ?Node root = null; ?// 將結(jié)果集存入映射表(后面將借助映射表構(gòu)造多叉樹) ?for (Iterator it = dataList.iterator(); it.hasNext();) { ? Map dataRecord = (Map) it.next(); ? Node node = new Node(); ? node.id = (String) dataRecord.get("id"); ? node.text = (String) dataRecord.get("text"); ? node.parentId = (String) dataRecord.get("parentId"); ? nodeList.put(node.id, node); ?} ?// 構(gòu)造無序的多叉樹 ?Set entrySet = nodeList.entrySet(); ?for (Iterator it = entrySet.iterator(); it.hasNext();) { ? Node node = (Node) ((Map.Entry) it.next()).getValue(); ? if (node.parentId == null || node.parentId.equals("")) { ? ?root = node; ? } else { ? ?((Node) nodeList.get(node.parentId)).addChild(node); ? } ?} ?// 輸出無序的樹形結(jié)構(gòu)的JSON字符串 ?System.out.println(root); ?// 對(duì)多叉樹進(jìn)行橫向排序 ?root.sortChildren(); ?// 輸出有序的樹形結(jié)構(gòu)的JSON字符串 ?System.out.println(root); ?// 程序輸出結(jié)果如下: ?// ?// 無序的樹形結(jié)構(gòu)(格式化后的結(jié)果,可使用JSON格式化工具查看,例如 ?http://jsonviewer.stack.hu/ 在線查看器): ? ?// ?{ ? // ? id : '100000', ? ? // ? text : '廊坊銀行總行', ? ?// ? children : [ ?// ? ? { ? // ? ? id : '110000', ? ? // ? ? text : '廊坊分行', ? ?// ? ? children : [ ?// ? ? ? { ? // ? ? ? id : '113000', ? ? // ? ? ? text : '廊坊銀行開發(fā)區(qū)支行', ? ?// ? ? ? leaf : true ?// ? ? ? }, ?// ? ? ? { ? // ? ? ? id : '111000', ? ? // ? ? ? text : '廊坊銀行金光道支行', ? ?// ? ? ? leaf : true ?// ? ? ? }, ?// ? ? ? { ? // ? ? ? id : '112000', ? ? // ? ? ? text : '廊坊銀行解放道支行', ? ?// ? ? ? children : [ ?// ? ? ? ? { ? // ? ? ? ? id : '112200', ? ? // ? ? ? ? text : '廊坊銀行三大街支行', ? ?// ? ? ? ? leaf : true ?// ? ? ? ? }, ?// ? ? ? ? { ? // ? ? ? ? id : '112100', ? ? // ? ? ? ? text : '廊坊銀行廣陽道支行', ? ?// ? ? ? ? leaf : true ?// ? ? ? ? } ?// ? ? ? ] ?// ? ? ? } ?// ? ? ] ?// ? ? } ?// ? ] ?// ?} ?// 有序的樹形結(jié)構(gòu)(格式化后的結(jié)果): ?// ?{ ? // ? id : '100000', ? ? // ? text : '廊坊銀行總行', ? ?// ? children : [ ?// ? ? { ? // ? ? id : '110000', ? ? // ? ? text : '廊坊分行', ? ?// ? ? children : [ ?// ? ? ? { ? // ? ? ? id : '111000', ? ? // ? ? ? text : '廊坊銀行金光道支行', ? ?// ? ? ? leaf : true ?// ? ? ? }, ?// ? ? ? { ? // ? ? ? id : '112000', ? ? // ? ? ? text : '廊坊銀行解放道支行', ? ?// ? ? ? children : [ ?// ? ? ? ? { ? // ? ? ? ? id : '112100', ? ? // ? ? ? ? text : '廊坊銀行廣陽道支行', ? ?// ? ? ? ? leaf : true ?// ? ? ? ? }, ?// ? ? ? ? { ? // ? ? ? ? id : '112200', ? ? // ? ? ? ? text : '廊坊銀行三大街支行', ? ?// ? ? ? ? leaf : true ?// ? ? ? ? } ?// ? ? ? ] ?// ? ? ? }, ?// ? ? ? { ? // ? ? ? id : '113000', ? ? // ? ? ? text : '廊坊銀行開發(fā)區(qū)支行', ? ?// ? ? ? leaf : true ?// ? ? ? } ?// ? ? ] ?// ? ? } ?// ? ] ?// ?} ? } } /** * 節(jié)點(diǎn)類 */ class Node { /** ?* 節(jié)點(diǎn)編號(hào) ?*/ public String id; /** ?* 節(jié)點(diǎn)內(nèi)容 ?*/ public String text; /** ?* 父節(jié)點(diǎn)編號(hào) ?*/ public String parentId; /** ?* 孩子節(jié)點(diǎn)列表 ?*/ private List children = new ArrayList(); // 添加孩子節(jié)點(diǎn) public void addChild(Node node) { ?children.add(node); } // 先序遍歷,拼接JSON字符串 public String toString() { ?String result = "{" + "id : '" + id + "'" + ", text : '" + text + "'"; ?if (children.size() != 0) { ? result += ", children : ["; ? for (int i = 0; i < children.size(); i++) { ? ? result += ((Node) children.get(i)).toString() + ","; ? ? ? } ? result = result.substring(0, result.length() - 1); ? result += "]"; ?} else { ? result += ", leaf : true"; ?} ?return result + "}"; } // 兄弟節(jié)點(diǎn)橫向排序 public void sortChildren() { ?if (children.size() != 0) { ? // 對(duì)本層節(jié)點(diǎn)進(jìn)行排序(可根據(jù)不同的排序?qū)傩?,傳入不同的比較器,這里 傳入ID比較器) ? Collections.sort(children, new NodeIDComparator()); ? ? // 對(duì)每個(gè)節(jié)點(diǎn)的下一層節(jié)點(diǎn)進(jìn)行排序 ? ? ? for (int i = 0; i < children.size(); i++) { ? ?((Node) children.get(i)).sortChildren(); ? } ?} } } /** * 節(jié)點(diǎn)比較器 */ class NodeIDComparator implements Comparator { // 按照節(jié)點(diǎn)編號(hào)比較 public int compare(Object o1, Object o2) { ?int j1 = Integer.parseInt(((Node) o1).id); ?int j2 = Integer.parseInt(((Node) o2).id); ?return (j1 < j2 ? -1 : (j1 == j2 ? 0 : 1)); } } /** * 構(gòu)造虛擬的層次數(shù)據(jù) */ class VirtualDataGenerator { // 構(gòu)造無序的結(jié)果集列表,實(shí)際應(yīng)用中,該數(shù)據(jù)應(yīng)該從數(shù)據(jù)庫中查詢獲得; public static List getVirtualResult() { ?List dataList = new ArrayList(); ?HashMap dataRecord1 = new HashMap(); ?dataRecord1.put("id", "112000"); ?dataRecord1.put("text", "廊坊銀行解放道支行"); ?dataRecord1.put("parentId", "110000"); ?HashMap dataRecord2 = new HashMap(); ?dataRecord2.put("id", "112200"); ?dataRecord2.put("text", "廊坊銀行三大街支行"); ?dataRecord2.put("parentId", "112000"); ?HashMap dataRecord3 = new HashMap(); ?dataRecord3.put("id", "112100"); ?dataRecord3.put("text", "廊坊銀行廣陽道支行"); ?dataRecord3.put("parentId", "112000"); ?HashMap dataRecord4 = new HashMap(); ?dataRecord4.put("id", "113000"); ?dataRecord4.put("text", "廊坊銀行開發(fā)區(qū)支行"); ?dataRecord4.put("parentId", "110000"); ?HashMap dataRecord5 = new HashMap(); ?dataRecord5.put("id", "100000"); ?dataRecord5.put("text", "廊坊銀行總行"); ?dataRecord5.put("parentId", ""); ?HashMap dataRecord6 = new HashMap(); ?dataRecord6.put("id", "110000"); ?dataRecord6.put("text", "廊坊分行"); ?dataRecord6.put("parentId", "100000"); ?HashMap dataRecord7 = new HashMap(); ?dataRecord7.put("id", "111000"); ?dataRecord7.put("text", "廊坊銀行金光道支行"); ?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); ?return dataList; } }
好了,通過上面的代碼,就可以實(shí)現(xiàn)多叉樹的兄弟節(jié)點(diǎn)橫向排序和先序遍歷了,實(shí)現(xiàn)了將層次數(shù)據(jù)轉(zhuǎn)換為有序無限級(jí)樹形結(jié)構(gòu)JSON字符串的目的。
在實(shí)際的項(xiàng)目中,可以把上面的有效代碼融入其中,或者在此基礎(chǔ)上進(jìn)行一些擴(kuò)展:
- 1、 實(shí)現(xiàn)對(duì)指定層次的排序(例如只排序第一層的節(jié)點(diǎn),或者只排序某一父節(jié)點(diǎn)下的所有子節(jié)點(diǎn))
- 2、 遍歷輸出樹形結(jié)構(gòu)時(shí)可以加入判斷條件過濾掉某些節(jié)點(diǎn)
- 3、 實(shí)現(xiàn)節(jié)點(diǎn)的刪除功能
- 4、 在節(jié)點(diǎn)類中增加一個(gè)父節(jié)點(diǎn)的引用,就可以計(jì)算出某一節(jié)點(diǎn)所處的級(jí)別
- 5、 在不支持層次查詢的數(shù)據(jù)庫應(yīng)用系統(tǒng)中使用該算法實(shí)現(xiàn)相同的效果
?四、思考與總結(jié)?
這篇文章的重點(diǎn)是如何構(gòu)造有序的無限級(jí)的樹形結(jié)構(gòu)JSON字符串,一次性生成樹形結(jié)構(gòu),而不是利用Ajax的方式,反復(fù)向服務(wù)器端發(fā)送請(qǐng)求,一級(jí)接一級(jí)的加載樹節(jié)點(diǎn)。
既然可以構(gòu)造無限級(jí)的JSON字符串,那么也可以根據(jù)這個(gè)思路構(gòu)造無限級(jí)的XML字符串,或者構(gòu)造具有層次結(jié)構(gòu)的UL – LI組合(用UL - LI來展示樹形結(jié)構(gòu)),或者構(gòu)造具有層次結(jié)構(gòu)的TABLE(用TABLE來展示樹形結(jié)構(gòu))。
如下所示:
(1)XML層次結(jié)構(gòu)
<nodeGroup id="100000" name="廊坊銀行總行"> <nodeGroup id="110000" name="廊坊分行"> ?<node id="113000" name="廊坊銀行開發(fā)區(qū)支行"> ? ?</node> ?<node id="111000" name="廊坊銀行金光道支行"> ? ?</node> ?<nodeGroup id="112000" name="廊坊銀行解放道支行"> ? ? <node id="112200" name="廊坊銀行三大街支行"> ? ? ? </node> ? ? <node id="112100" name="廊坊銀行廣陽道支行"> ? ? ? </node> ?</nodeGroup> </nodeGroup> </nodeGroup>
(2)UL - LI 層次結(jié)構(gòu)
<ul> <li>廊坊銀行總行</li> <ul> ?<li>廊坊分行</li> ?<ul> ? ? <li>廊坊銀行開發(fā)區(qū)支行</li> ? ? ? ? ? <li>廊坊銀行解放道支行</li> ? ? <ul> ? ? ?<li>廊坊銀行三大街支行</li> ? ? ?<li>廊坊銀行廣陽道支行</li> ? ? ?</ul> ? ? ?<li>廊坊銀行金光道支行</li> ? </ul> ? ? </ul> ? </ul>
(3)TABLE層次結(jié)構(gòu)
<table> <tr><td>廊坊銀行總行</td></tr> <tr><td> 廊坊分行</td></tr> <tr><td> 廊坊銀行開發(fā)區(qū)支行</td></tr> <tr><td> 廊坊銀行解放道支行</td></tr> <tr><td> 廊坊銀行三大街支行</td></tr> <tr><td> 廊坊銀行廣陽道支行</td></tr> <tr><td> 廊坊銀行金光道支行</td></tr> </table>
另外對(duì)TreeGrid樹形表格也有一定的價(jià)值:
- 1、 一次性構(gòu)造樹形表格,實(shí)現(xiàn)數(shù)據(jù)分級(jí)展示
- 2、 通過更換比較器,實(shí)現(xiàn)對(duì)不同表格列的全排序(全排序指的是對(duì)所有頁的數(shù)據(jù)進(jìn)行排序,而不是只對(duì)當(dāng)前頁的數(shù)據(jù)排序;排序規(guī)則與Oracle數(shù)據(jù)庫中的層次查詢類似,即兄弟節(jié)點(diǎn)橫向排序)
- 3、 實(shí)現(xiàn)對(duì)樹形表格的完整分頁(每次分頁時(shí),只取固定數(shù)目的第一層節(jié)點(diǎn),之后調(diào)用toString方法,展示出完整條數(shù)的分級(jí)數(shù)據(jù),即每頁的記錄條數(shù)是不固定的,但必須是完整的樹形結(jié)構(gòu))
到此這篇關(guān)于JavaScript樹形組件實(shí)現(xiàn)無限級(jí)樹形結(jié)構(gòu)的文章就介紹到這了,更多相關(guān)JavaScript無限級(jí)樹形結(jié)構(gòu)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
asp javascript 實(shí)現(xiàn)關(guān)閉窗口時(shí)保存數(shù)據(jù)的辦法
asp javascript 實(shí)現(xiàn)關(guān)閉窗口時(shí)保存數(shù)據(jù)的辦法...2007-11-11javascript跨域方法、原理以及出現(xiàn)問題解決方法(詳解)
javascript出于安全方面的考慮,不允許跨域調(diào)用其他頁面的對(duì)象。但是在安全限制的同時(shí)也給注入iframe或是ajax應(yīng)用上帶來了不少麻煩??缬蚝唵蔚睦斫饩褪且?yàn)閖avascript同源策略的限制,a.com域名下的js無法操作b.com 或者是c.a.com域名下的對(duì)象2015-08-08JavaScript求一組數(shù)的最小公倍數(shù)和最大公約數(shù)常用算法詳解【面向?qū)ο?,回歸迭代和循環(huán)】
這篇文章主要介紹了JavaScript求一組數(shù)的最小公倍數(shù)和最大公約數(shù)常用算法,結(jié)合實(shí)例形式分析了javascript基于面向?qū)ο螅貧w迭代和循環(huán)等算法求解一組數(shù)的最小公倍數(shù)與最大公約數(shù)相關(guān)操作技巧,需要的朋友可以參考下2018-05-05Object的相關(guān)方法 和 js遍歷對(duì)象的常用方法總結(jié)
這篇文章主要介紹了Object的相關(guān)方法 和 js遍歷對(duì)象的常用方法,結(jié)合實(shí)例形式總結(jié)分析了Object對(duì)象操作的操作方法與js遍歷的三種常用方法,需要的朋友可以參考下2023-05-05Json字符串轉(zhuǎn)換為JS對(duì)象的高效方法實(shí)例
一般JSON字符串轉(zhuǎn)換為JS對(duì)象,都使用var jsonStr="{a:1}";var jsonObj = eval("("+jsonStr+")");2013-05-05