Posted on 2006-01-27 16:42
-=Kinohl=- 閱讀(2706)
評論(7) 編輯 收藏 所屬分類:
編程語言
***************************************
關鍵字:AJAX,Tree,Struts,DOM
難易度: 中
軟件版本:struts 1.2.8
時間:2006-01-27
Author:Kino
***************************************
前陣子寫了一個小代碼處理AJAX下WebTree的構建,其中碰到了一些問題,也有一些想法,現在說出來希望大家一起看看,如果案由問題請不吝賜教,本人不勝感激啊。
背景:
這次因為是加載在Struts上的開發,Web頁面上的Tree作AJAX處理,因為有Node的增刪改操作。Server端因為要和WebService連接,所以不做Cache。
解決案:
1。使用Polling調用AJAX定期更新Tree。
2。AJAX訪問的地址是一個Action(例:createtree.do)。用來返回Tree模型或者錯誤消息(國際化)。
3。Browser解析XML的TreeModel。
4。在Browser比較新舊2個TreeModel,完成選中狀態的繼承。
5。CSS渲染TreeNode。
以上是簡單的思路。傳統的AJAX應該是盡量減少XMl傳輸量,迫于沒有Cache的緣故,并且WS給我的節點并不能簡單的得到父子關系。我選擇了,每次Polling更新整棵樹的方案。性能未測。
我這次在web server 端構建Tree時直接用深度優先轉換成XML。XMl中數據的先后順序決定了Tree從父到子,從兄到弟的深度優先關系,indent決定了深度(也就是縮進)。這樣我從Server端傳入的也就成了一個標準的Tree顯示Model。格式定義如下。
* Gobal Master Tree DTD
* <!ELEMENT tree (tree*)>
* <!ATTLIST tree
* id CDATA #REQUIRED LoctionInfo's toString
* indent CDATA #REQUIRED Tree's Level
* text CDATA #REQUIRED label in html
* tooltip CDATA #IMPLIED title in html
* action CDATA #IMPLIED href in html
* icon CDATA #IMPLIED close icon with the node status
* openicon CDATA #IMPLIED open icon with the node status
* open CDATA #IMPLIED> node's open states ,default is false in server.
* target CDATA #IMPLIED node's open target
*
<span id="maintree">
<tree id="Ajax" indent=0 text="Root" tooltip="Root" action="/logout.do" icon="" openicon= "" open="false"/>
<tree id="110" indent=1 text="Node 1" tooltip="Node 1" action="/logout.do" icon="" openicon= "" open="false"/>
<tree id="120" indent=2 text="Node 2" tooltip="Node 2" action="/logout.do" icon="" openicon= "" open="false"/>
<tree id="12580" indent=2 text="Node 3" tooltip="Node 3" action="/logout.do" icon="" openicon= "" open="false"/>
<tree id="user" indent=1 text="Node 4" tooltip="Node 4" action="/logout.do" icon="" openicon= "" open="false"/>
</span>
上邊的 Tree顯示出來如下
Root
│
├Node 1
│ │
│ ├Node 2
│ └Node 3
└Node 4
indent 就是縮進。
數據的先后順序就是深度優先的遍歷順序。
這樣的數據到了Browser,會先被轉成一個對象數組。
1
// Tree Node object
2
// This function creates a node in the tree with the following arguments:
3
// sId - The node's index within the global nodes_array
4
// iIndent - The level within the tree hierarchy (0 = top)
5
// sText - The text displayed in the tree for this node
6
// sTooltip - the tool tip
7
// oAction - For a document, the address it will display when clicked
8
// sIcon - the node's icon
9
// sIconOpen - the node's icon state
10
// bOpen - true false
11
function GMTreeNode(sId,iIndent,sText,sTooltip,sAction,sIcon,sIconOpen,bOpen,sTarget)
12

{
13
if (sId) this.id = sId;
14
if (iIndent) this.indent = iIndent;
15
if (sText) this.text = sText;
16
if (sAction) this.action = sAction;
17
if (sTooltip) this.tooltip = sTooltip;
18
if (sIcon) this.icon = sIcon;
19
if (sIconOpen) this.iconopen = sIconOpen;
20
if (bOpen) this.open = bOpen;
21
if (sTarget) this.target = sTarget;
22
23
// //alert(this.id + " " + this.indent + " " + this.text + " " + this.action + " " +
24
// this.tooltip + " " + this.icon + " " + this.iconopen + " " + this.open);
25
} 然后會和正在顯示的Tree數組 進行一個 比較,用于寫入展開狀態,代碼如下:
1
/////////////////////////////////
2
// >>>Compare
3
// compare maintree with maintree. and copy maintree to maintree
4
/////////////////////////////////
5
function compareTreeModel()
6

{
7
//alert("I am here in compareTreeModel");
8
if (ajaxtree.length <= 0)
{
9
alert("ajaxtree is null");//TODO
10
return;
11
}
12
13
if (maintree.length <= 0)
{
14
//alert("maintree is null");
15
maintree = ajaxtree;
16
return;
17
}
18
//compare start
19
//var maxlen = Math.max(ajaxtree.length,maintree.length);
20
for(var i=0;i<ajaxtree.length;i++)
21
{
22
for(var j=0;j<maintree.length;j++)
23
{
24
if (ajaxtree[i].id == maintree[j].id)
25
{
26
ajaxtree[i].open = maintree[j].open;
27
break;
28
}
29
}
30
}
31
32
maintree = ajaxtree;
33
34
} maintree 就是正在顯示的 Tree,ajaxtree是剛得到的新Tree。2個對象都是TreeNode的數組。而TreeNode對象的Open屬性即記錄了節點的展開狀態。那么這里就對這個節點狀態進行“移植”,完畢后,把新Tree模型交付顯示方法,也就是ToHtml方法。
轉換Html部分算是一個比較容易出bug的危險點。
首先分析一下,生成的代碼是什么樣子的。
這里仍然用上邊的那棵樹作例子。
生成的DOM結構應該是
<div 父>
<div 收縮>
<img 折線 />
<img 圖標 />
<a 節點動作>節點Label</a>
<div 子>
....遞歸的構造
</div 子>
</div 收縮>
</div 父>
其次 對于這種并不直接含有父子關系的節點首先要判明一個節點的子 和 兄弟,然后用遞歸解決。
遞歸的思路如下深度優先:
function toHtml(節點index)
{
var child_html;
if 這個節點有子
{
Loop子節點
{
child_html[i] = toHtml(子節點index);
i++;訪問下一個子節點
}
var 所有子節點Html模塊 = <div 收縮> child_html.join("") </div>
var 本節點Html模塊 = <div 本節點><div 收縮><img ><img 圖標 /><a 節點動作>節點Label</a>所有子節點Html模塊</div 收縮></div 本節點>;
return 本節點Html模塊;
}
樹就構建好了。
作為顯示,使用了CSS的
background-repeat: repeat-y;
background-image: url("../images/tree/I.png") !important;
background-position-y: 1px !important; /* IE only */
還有padding-left作Div的向右偏移,默認的偏移量是19個像素點,然后根據Tree顯示模型的indent相乘就ok了。
思路就是這些。希望能對 朋友們有所幫助。
歡迎討論。