轉(zhuǎn)帖|其它|編輯:郝浩|2010-08-11 10:04:42.000|閱讀 922 次
概述:樹(shù)形控件是一種人們熟悉的用戶界面控件,廣泛地用來(lái)顯示層次型數(shù)據(jù)。樹(shù)形控件具有獨(dú)特的擴(kuò)展和折疊分支的能力,能夠以較小的空間顯示出大量的信息,一目了然地傳達(dá)出數(shù)據(jù)之間的層次關(guān)系。凡是熟悉圖形用戶界面的用戶,都能夠自如地運(yùn)用樹(shù)形控件。
# 界面/圖表報(bào)表/文檔/IDE等千款熱門(mén)軟控件火熱銷(xiāo)售中 >>
樹(shù)形控件是一種人們熟悉的用戶界面控件,廣泛地用來(lái)顯示層次型數(shù)據(jù)。
樹(shù)形控件具有獨(dú)特的擴(kuò)展和折疊分支的能力,能夠以較小的空間顯示出大量的信息,一目了然地傳達(dá)出數(shù)據(jù)之間的層次關(guān)系。凡是熟悉圖形用戶界面的用戶,都能夠自如地運(yùn)用樹(shù)形控件。
HTML本身不支持樹(shù)形控件,但我們可以通過(guò)一些JavaScript腳本代碼實(shí)現(xiàn)。為了提高控件的可重用性,我們要充分運(yùn)用JavaScript對(duì)面向?qū)ο缶幊碳夹g(shù)的支持。本文的樹(shù)形控件適用于IE 4+和Netscape 6.x,應(yīng)當(dāng)說(shuō)這已經(jīng)涵蓋了當(dāng)前的主流瀏覽器。
一、JavaScript與面向?qū)ο?/strong>
面向?qū)ο蟮木幊逃腥齻€(gè)最基本的概念:繼承,封裝,多態(tài)性。繼承和封裝這兩個(gè)概念比較好理解,相對(duì)而言,多態(tài)性這個(gè)概念就比較難于掌握和運(yùn)用。一般而言,多態(tài)性是指以多種形式表現(xiàn)的能力。在面向?qū)ο缶幊碳夹g(shù)中,多態(tài)性表示編程語(yǔ)言擁有的一種根據(jù)對(duì)象的數(shù)據(jù)類(lèi)型或類(lèi)的不同而采取不同處理方式的能力。
在“純”面向?qū)ο蟮恼Z(yǔ)言中,例如Java,多態(tài)性一般與類(lèi)的繼承密不可分。也就是說(shuō),必須定義一種類(lèi)的層次關(guān)系,處于頂端的是抽象類(lèi),處于下層的是各種具體的實(shí)現(xiàn)。抽象類(lèi)定義了子類(lèi)必須實(shí)現(xiàn)或覆蓋的方法,不同的子類(lèi)根據(jù)自己的需要以不同的方式覆蓋抽象類(lèi)的方法。
例如,計(jì)算圓面積和矩形面積的公式完全不同,按照面向?qū)ο蟮脑O(shè)計(jì)思路,我們要先定義一個(gè)抽象類(lèi)Shape,Sharp類(lèi)有一個(gè)findArea()方法,所有從Shape類(lèi)派生的子類(lèi)都必須實(shí)現(xiàn)findArea()方法。然后,我們定義一個(gè)代表矩形的Rectangle類(lèi),一個(gè)代表圓的Circle類(lèi),這兩個(gè)類(lèi)都從Shape類(lèi)繼承。Rectangle類(lèi)和Circle類(lèi)分別實(shí)現(xiàn)findArea()方法,兩者用不同的計(jì)算公式計(jì)算面積。最終達(dá)到這樣一個(gè)目標(biāo):不論對(duì)象屬于Shape的哪一種子類(lèi)(Rectangle或Circle),都可以用相同的方式調(diào)用findArea()方法,不用去管被調(diào)用的findArea()采用什么公式計(jì)算面積,從而有效地隱藏實(shí)現(xiàn)細(xì)節(jié)。
JavaScript語(yǔ)言不支持以類(lèi)為基礎(chǔ)的繼承,但仍具有支持多態(tài)性的能力。JavaScript的繼承是一種基于原型(Prototype)的繼承。實(shí)際上,正如本文例子所顯示的,這種繼承方式簡(jiǎn)化了多態(tài)性方法的編寫(xiě),而且從結(jié)構(gòu)上來(lái)看,最終得到的程序也與純面向?qū)ο笳Z(yǔ)言很接近。
二、準(zhǔn)備工作
整個(gè)樹(shù)形控件由四部分構(gòu)成:圖形,CSS樣式定義,HTML框架代碼,JavaScript代碼。從圖一可以看出,樹(shù)形控件需要三個(gè)圖形,分別表示折疊的分支(closed.gif)、展開(kāi)的分支(open.gif)和葉節(jié)點(diǎn)(doc.gif)。
下面是樹(shù)形控件要用到的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規(guī)則很簡(jiǎn)單:body規(guī)則設(shè)置了文檔的字體和前景(文字)顏色。branch規(guī)則的用途是:當(dāng)鼠標(biāo)經(jīng)過(guò)擁有子節(jié)點(diǎn)的節(jié)點(diǎn)時(shí),指針會(huì)變成手的形狀。之所以要定義兩個(gè)cursor屬性,是因?yàn)镮E和Netscape使用不同的屬性名稱。在leaf規(guī)則中設(shè)置display屬性為none,這是為了實(shí)現(xiàn)葉節(jié)點(diǎn)(不含子節(jié)點(diǎn)的最終節(jié)點(diǎn))的折疊效果。在腳本代碼中,我們通過(guò)把display屬性設(shè)置成block顯示出節(jié)點(diǎn),設(shè)置成none隱藏節(jié)點(diǎn)。
三、腳本設(shè)計(jì)
本文實(shí)現(xiàn)的樹(shù)形控件包含一個(gè)tree對(duì)象,tree對(duì)象擁有一個(gè)branches子對(duì)象集合;每一個(gè)branch(分支)對(duì)象又擁有一個(gè)子對(duì)象的集合。子對(duì)象可以是branch對(duì)象,也可以是leaf(樹(shù)葉)對(duì)象。所有這三種對(duì)象分別實(shí)現(xiàn)一個(gè)多態(tài)性的write()方法,不同對(duì)象的write()方法根據(jù)所屬對(duì)象的不同而執(zhí)行不同的操作,也就是說(shuō):tree對(duì)象的write()方法與branch對(duì)象的write()方法不同,branch對(duì)象的write()方法又與leaf對(duì)象的write()方法不同。另外,tree和branch對(duì)象各有一個(gè)add()方法,分別用來(lái)向各自所屬的對(duì)象添加子對(duì)象。
在HTML文檔的部分加入下面這段代碼。這段代碼的作用是創(chuàng)建兩個(gè)Image對(duì)象,分別對(duì)應(yīng)分支打開(kāi)、折疊狀態(tài)的文件夾圖形。另外還有幾個(gè)工具函數(shù),用于打開(kāi)或折疊任意分支的子元素,同時(shí)根據(jù)分支的打開(kāi)或折疊狀態(tài)相應(yīng)地變換文件夾圖形。
< 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>
代碼預(yù)先裝入圖形對(duì)象,這有利于提高以后的顯示速度。showBranch()函數(shù)首先獲得參數(shù)提供的分支的樣式,判斷并切換當(dāng)前樣式的顯示屬性(在block和none之間來(lái)回切換),從而形成分支的擴(kuò)展和折疊效果。swapImage()函數(shù)的原理和showBranch()函數(shù)基本相同,它首先判斷當(dāng)前分支的圖形(打開(kāi)的文件夾還是折疊的文件夾),然后切換圖形。
四、tree對(duì)象
下面是tree對(duì)象的構(gòu)造函數(shù):
function tree(){
this.branches = new Array();
this.add = addBranch;
this.write = writeTree;
}
tree對(duì)象代表著整個(gè)樹(shù)形結(jié)構(gòu)的根。tree()構(gòu)造函數(shù)創(chuàng)建了branches數(shù)組,這個(gè)數(shù)組用來(lái)保存所有的子元素。add和write屬性是指向兩個(gè)多態(tài)性方法的指針,兩個(gè)多態(tài)性方法的實(shí)現(xiàn)如下:
function addBranch(branch){
this.branches[this.branches.length] = branch;
}
function writeTree(){
var treeString = '';
var numBranches = this.branches.length;
for (var i=0;i
treeString += this.branches[i].write();
document.write(treeString);
}
addBranch()方法把參數(shù)傳入的對(duì)象加入到branches數(shù)組的末尾。writeTree()方法遍歷保存在branches數(shù)組中的每一個(gè)對(duì)象,調(diào)用每一個(gè)對(duì)象的write()方法。注意這里利用了多態(tài)性的優(yōu)點(diǎn):不管branches數(shù)組的當(dāng)前元素是什么類(lèi)型的對(duì)象,我們只需按照統(tǒng)一的方式調(diào)用write()方法,實(shí)際執(zhí)行的write()方法由branches數(shù)組當(dāng)前元素的類(lèi)型決定——可能是branch對(duì)象的write()方法,也可能是leaf對(duì)象的write()方法。
必須說(shuō)明的是,雖然JavaScript的Array對(duì)象允許保存任何類(lèi)型的數(shù)據(jù),但這里我們只能保存實(shí)現(xiàn)了write()方法的對(duì)象。象Java這樣的純面向?qū)ο笳Z(yǔ)言擁有強(qiáng)健的類(lèi)型檢查機(jī)制,能夠自動(dòng)報(bào)告類(lèi)型錯(cuò)誤;但JavaScript這方面的限制比較寬松,我們必須手工保證保存到branches數(shù)組的對(duì)象具有正確的類(lèi)型。
五、branch對(duì)象
branch對(duì)象與tree對(duì)象相似:
function branch(id, text){
this.id = id;
this.text = text;
this.write = writeBranch;
this.add = addLeaf;
this.leaves = new Array();
}
branch對(duì)象的構(gòu)造函數(shù)有id和text兩個(gè)參數(shù)。id是一個(gè)唯一性的標(biāo)識(shí)符,text是顯示在該分支的文件夾之后的文字。leaves數(shù)組是該分支對(duì)象的子元素的集合。注意branch對(duì)象定義了必不可少的write()方法,因此可以保存到tree對(duì)象的branches數(shù)組。tree對(duì)象和branch對(duì)象都定義了write()和add()方法,所以這兩個(gè)方法都是多態(tài)性的。下面是branch對(duì)象的add()和write()方法的具體實(shí)現(xiàn):
function addLeaf(leaf){
this.leaves[this.leaves.length] = leaf;
}
function writeBranch(){
var branchString =
'< span class="branch" ' + onClick="showBranch(\'' + this.id + '\')"';
branchString += '>< img src="//www.webjx.com/htmldata/sort/closed.gif" id="I' + this.id + '">' + this.text;
branchString += '< /span>';
branchString += '< span class="leaf" id="';
branchString += this.id + '">';
var numLeaves = this.leaves.length;
for (var j=0;j< numLeaves;j++) branchString += this.leaves[j].write();
branchString += '< /span>';
return branchString;
}
addLeaf()函數(shù)和tree對(duì)象的addBranch()函數(shù)相似,它把通過(guò)參數(shù)傳入的對(duì)象加入到leaves數(shù)組的末尾。
writeBranch()方法首先構(gòu)造出顯示分支所需的HTML字符串,然后通過(guò)循環(huán)遍歷leaves數(shù)組中的每一個(gè)對(duì)象,調(diào)用數(shù)組中每一個(gè)對(duì)象的write()方法。和branches數(shù)組一樣,leaves數(shù)組也只能保存帶有write()方法的對(duì)象。
六、leaf對(duì)象
leaf對(duì)象是三個(gè)對(duì)象之中最簡(jiǎn)單的一個(gè):
function leaf(text, link){
this.text = text;
this.link = link;
this.write = writeLeaf;
}
leaf對(duì)象的text屬性表示要顯示的文字,link屬性表示鏈接。如前所述,leaf對(duì)象也要定義write()方法,它的實(shí)現(xiàn)如下:
function writeLeaf(){
var leafString = '< a href="' + this.link + '">';
leafString += '< img src="//www.webjx.com/htmldata/sort/doc.gif" border="0">';
leafString += this.text;
leafString += '< /a>< br>';
return leafString;
}
writeLeaf()函數(shù)的作用就是構(gòu)造出顯示當(dāng)前節(jié)點(diǎn)的HTML字符串。leaf對(duì)象不需要實(shí)現(xiàn)add()方法,因?yàn)樗?是分支的終結(jié)點(diǎn),不包含子元素。
七、裝配樹(shù)形控件
最后要做的就是在HTML頁(yè)面中裝配樹(shù)形控件了。構(gòu)造過(guò)程很簡(jiǎn)單:創(chuàng)建一個(gè)tree對(duì)象,然后向tree對(duì)象添加分支節(jié)點(diǎn)和葉節(jié)點(diǎn)。構(gòu)造好整個(gè)樹(shù)形結(jié)構(gòu)之后,調(diào)用tree對(duì)象的write()方法把樹(shù)形控件顯示出來(lái)。下面是一個(gè)多層的樹(shù)形結(jié)構(gòu),只要把它加入標(biāo)記內(nèi)需要顯示樹(shù)形控件的位置即可。注意下面例子中凡是應(yīng)該加入鏈接的地方都以“#”替代:
< script language="JavaScript">
var myTree = new tree();
var branch1 = new branch('branch1','JavaScript參考書(shū)');
var leaf1 = new leaf('前言','#');
var leaf2 = new leaf('緒論','#');
branch1.add(leaf1);
branch1.add(leaf2);
myTree.add(branch1);
var branch2 = new branch('branch2','第一章');
branch2.add(new leaf('第一節(jié)','#'));
branch2.add(new leaf('第二節(jié)','#'));
branch2.add(new leaf('第三節(jié)','#'));
branch1.add(branch2);
var branch3 = new branch('branch2','第二章');
branch3.add(new leaf('第一節(jié)','#'));
branch3.add(new leaf('第二節(jié)','#'));
branch3.add(new leaf('第三節(jié)','#'));
branch1.add(branch3);
myTree.add(new leaf('聯(lián)系我們','#'));
myTree.write();
< /script>
上述代碼的運(yùn)行效果如圖一所示。可以看到,裝配樹(shù)形控件的代碼完全符合面向?qū)ο蟮娘L(fēng)格,簡(jiǎn)潔高效。
從本質(zhì)上看,用面向?qū)ο蠹夹g(shù)構(gòu)造的樹(shù)形控件包含一組對(duì)象,而且這組對(duì)象實(shí)現(xiàn)了純面向?qū)ο蟮恼Z(yǔ)言中稱為接口的東西,只不過(guò)由于JavaScript語(yǔ)言本身的限制,接口沒(méi)有明確定義而已。例如,本文的樹(shù)形控件由tree、branch、leaf三個(gè)對(duì)象構(gòu)成,而且這三個(gè)對(duì)象都實(shí)現(xiàn)了write接口,也就是說(shuō),這三個(gè)對(duì)象都有一個(gè)write()方法,不同對(duì)象的write()方法根據(jù)對(duì)象類(lèi)型的不同提供不同的功能。又如,tree、branch對(duì)象實(shí)現(xiàn)了add接口,兩個(gè)對(duì)象分別根據(jù)自身的需要定義了add()方法的不同行為。可見(jiàn),多態(tài)性是面向?qū)ο蠹夹g(shù)中一個(gè)重要的概念,它為構(gòu)造健壯的、可伸縮的、可重用的代碼帶來(lái)了方便。
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請(qǐng)務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請(qǐng)郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自:網(wǎng)絡(luò)轉(zhuǎn)載