樹形控制項是一種人們熟悉的使用者介面控制項,廣泛地用來顯示層次型資料。
樹形控制項具有獨特 的擴充和摺疊分支的能力,能夠以較小的空間顯示出大量的資訊,一目瞭然地傳達出資料之間的層次關 系。凡是熟悉圖形化使用者介面的使用者,都能夠自如地運用樹形控制項。
圖一:用JavaScript 實現的樹形控制項
HTML本身不支援樹形控制項,但我們可以通過一些JavaScript指令碼代碼實現。為了 提高控制項的可重用性,我們要充分運用JavaScript對物件導向編程技術的支援。本文的樹形控制項適用於 IE 4+和Netscape 6.x,應當說這已經涵蓋了當前的主流瀏覽器。
一、JavaScript與物件導向
物件導向的編程有三個最基本的概念:繼承,封裝,多態性。繼承和封裝這兩個概念比較好理解 ,相對而言,多態性這個概念就比較難於掌握和運用。一般而言,多態性是指以多種形式表現的能力。 在物件導向編程技術中,多態性表示程式設計語言擁有的一種根據對象的資料類型或類的不同而採取不同處 理方式的能力。
在“純”物件導向的語言中,例如Java,多態性一般與類的繼承密不 可分。也就是說,必須定義一種類的層次關係,處於頂端的是抽象類別,處於下層的是各種具體的實現。 抽象類別定義了子類必須實現或覆蓋的方法,不同的子類根據自己的需要以不同的方式覆蓋抽象類別的方法 。
例如,計算圓面積和矩形面積的公式完全不同,按照物件導向的設計思路,我們要先定義一個 抽象類別Shape,Sharp類有一個findArea()方法,所有從Shape類派生的子類都必須實現findArea()方法。 然後,我們定義一個代表矩形的Rectangle類,一個代表圓的Circle類,這兩個類都從Shape類繼承。 Rectangle類和Circle類分別實現findArea()方法,兩者用不同的計算公式計算面積。最終達到這樣一個 目標:不論對象屬於Shape的哪一種子類(Rectangle或Circle),都可以用相同的方式調用findArea()方 法,不用去管被調用的findArea()採用什麼公式計算面積,從而有效地隱藏實現細節。
JavaScript語言不支援以類為基礎的繼承,但仍具有支援多態性的能力。JavaScript的繼承是一 種基於原型(Prototype)的繼承。實際上,正如本文例子所顯示的,這種繼承方式簡化了多態性方法的編 寫,而且從結構上來看,最終得到的程式也與純物件導向語言很接近。
二、準備工作
整 個樹形控制項由四部分構成:圖形,CSS樣式定義,HTML架構代碼,JavaScript代碼。從圖一可以看出,樹 形控制項需要三個圖形,分別表示摺疊的分支(closed.gif)、展開的分支(open.gif)和分葉節點(doc.gif)。
下面是樹形控制項要用到的CSS樣式定義:
< style>
body{
font: 10pt 宋體,sans-serif; color: navy; }
.branch{
cursor: pointer;
cursor: hand;
display: block; }
.leaf{
display: none;
margin-left: 16px; }
a{ text-decoration: none; }
a:hover{ text-decoration: underline; }
< /style>
CSS規則很簡單 :body規則設定了文檔的字型和前景(文字)顏色。branch規則的用途是:當滑鼠經過擁有子節點的節點 時,指標會變成手的形狀。之所以要定義兩個cursor屬性,是因為IE和Netscape使用不同的屬性名稱。 在leaf規則中設定display屬性為none,這是為了實現分葉節點(不含子節點的最終節點)的摺疊效果。在腳 本代碼中,我們通過把display屬性設定成block顯示出節點,設定成none隱藏節點。
三、指令碼設 計
本文實現的樹形控制項包含一個tree對象,tree對象擁有一個branches子物件集合;每一個 branch(分支)對象又擁有一個子物件的集合。子物件可以是branch對象,也可以是leaf(樹葉)對象。所 有這三種對象分別實現一個多態性的write()方法,不同對象的write()方法根據所屬對象的不同而執行 不同的操作,也就是說:tree對象的write()方法與branch對象的write()方法不同,branch對象的 write()方法又與leaf對象的write()方法不同。另外,tree和branch對象各有一個add()方法,分別用來 向各自所屬的對象添加子物件。
在HTML文檔的部分加入下面這段代碼。這段代碼的作用是建立兩 個Image對象,分別對應分支開啟、摺疊狀態的檔案夾圖形。另外還有幾個工具函數,用於開啟或摺疊任 意分支的子項目,同時根據分支的開啟或摺疊狀態相應地變換檔案夾圖形。
< script language="JavaScript">
var openImg = new ..Asset not found..;
openImg.src = "open.gif";
var closedImg = new ..Asset not found..;
closedImg.src = "closed.gif";
function showBranch (branch){
var objBranch = document.getElementById(branch).style;
if (objBranch.display=="block")
objBranch.display="none";
else
objBranch.display="block";
swapFolder('I' + branch);
}
function swapFolder(img){
objImg = document.getElementById(img);
if (objImg.src.indexOf('closed.gif')>-1)
objImg.src = openImg.src;
else
objImg.src = closedImg.src;
}
< /script>
代碼預先裝入繪圖物件,這有利於提高以後的顯示 速度。showBranch()函數首先獲得參數提供的分支的樣式,判斷並切換當前樣式的顯示內容(在block和 none之間來回切換),從而形成分支的擴充和摺疊效果。swapImage()函數的原理和showBranch()函數基 本相同,它首先判斷當前分支的圖形(開啟的檔案夾還是摺疊的檔案夾),然後切換圖形。