筆者日前涉及一個(gè)大型ASP項(xiàng)目的開發(fā),其中多次遇到多維下拉菜單(對(duì)于WEB項(xiàng)目而言,這里專指網(wǎng)頁(yè)中的<SELECT>元素)的問題,菜單中的數(shù)據(jù)均需要從數(shù)據(jù)庫(kù)中取出,并動(dòng)態(tài)的生成和變化。筆者以前曾發(fā)表過(guò)如何利用PHP和JavaScript制作二維下拉菜單的文章,目前這類文章在網(wǎng)絡(luò)上也頗為多見,思路也有很多創(chuàng)新,但對(duì)于本文中談到的多維下拉菜單,很少有人談及。筆者無(wú)意班門弄斧,只是想把開發(fā)中的一點(diǎn)經(jīng)驗(yàn)和技巧總結(jié)出來(lái),希望能給廣大的讀者一點(diǎn)啟示。
多維下拉菜單,顧名思義,也就是根據(jù)一個(gè)下拉菜單的選擇,來(lái)控制其它一個(gè)或多個(gè)下拉菜單中顯示的數(shù)據(jù)。舉個(gè)例子來(lái)說(shuō)明,在一個(gè)WEB管理系統(tǒng)中,用戶要求通過(guò)選擇單位名稱,進(jìn)而選擇部門名稱,最后選擇員工。也就是說(shuō),需要提供三個(gè)下拉列表,每個(gè)下拉列表之間需要建立關(guān)聯(lián)。通過(guò)第一個(gè)能選擇第二個(gè),并同時(shí)選擇第三個(gè),第四個(gè)等等。那么每一個(gè)下拉列表的顯示數(shù)據(jù)之間如何建立關(guān)聯(lián),關(guān)聯(lián)起來(lái)的數(shù)據(jù)又如何通過(guò)事件驅(qū)動(dòng),這正是本文所要討論的主要內(nèi)容。
熟悉VB、Delphi等RAD開發(fā)工具的朋友可能會(huì)感到疑惑。的確,在這些所謂的RAD開發(fā)工具中,我們可以利用Combo Boxes控件很容易的實(shí)現(xiàn)下拉菜單,進(jìn)而實(shí)現(xiàn)他們之間的關(guān)聯(lián)。但是由于WEB項(xiàng)目中的下拉菜單是利用HTML中的<SELECT>元素來(lái)實(shí)現(xiàn)的,而由于HTML的局限性,無(wú)論是對(duì)象的屬性還是事件模型,都遠(yuǎn)沒有RAD工具那么強(qiáng)大。所以,開發(fā)WEB項(xiàng)目,這種問題只能有一個(gè)解決途徑,那就是利用JavaScript(也可能有人說(shuō)可以利用java來(lái)實(shí)現(xiàn),那我也只好說(shuō),您是高手)。 關(guān)于JavaScript的使用,不是本文的重點(diǎn),所以不了解或不熟悉JavaScript的讀者請(qǐng)先參考JavaScript的相關(guān)資料以獲取相關(guān)信息。
好,言歸正傳,下面我們就一起來(lái)探討多維下拉菜單的設(shè)計(jì)問題。為了討論的方便,我們就以上文提到的三維下拉菜單為例,向大家一步一步的講述設(shè)計(jì)的思路。
一、分析菜單的運(yùn)作流程
首先,用戶會(huì)選擇單位列表,并從中選出一個(gè)單位名稱,我們假定為單位A。這時(shí),另外兩個(gè)下拉列表應(yīng)該做些什么?對(duì),我們希望第二個(gè)下拉菜單能立即反映第一個(gè)下拉菜單的選擇,顯示并僅顯示單位A中的所有部門,我們?cè)偌俣ú藛沃械谝豁?xiàng)為部門A(默認(rèn)的顯示項(xiàng))。那么可能有讀者會(huì)問,第三個(gè)下拉菜單不是應(yīng)該同時(shí)選擇與部門A對(duì)應(yīng)的員工數(shù)據(jù)嗎?這是個(gè)很好的想法,是的,我們也應(yīng)該立即改變第三個(gè)下拉菜單中的數(shù)據(jù)為部門A中的員工列表。同樣,當(dāng)用戶選擇部門時(shí),又會(huì)改變員工列表。依次類推。 以上是一種思路,可能有一些特殊的情況,例如,在改變部門列表時(shí),并不希望立即就選擇一個(gè)部門,而是顯示一個(gè)"請(qǐng)選擇"字樣的提示條目。 思路已經(jīng)有了,下面就是如何實(shí)現(xiàn)的問題了。
二、菜單數(shù)據(jù)的容器
根據(jù)常規(guī)想法,當(dāng)用戶從第一個(gè)下拉菜單中選擇單位名稱,我們可以從數(shù)據(jù)庫(kù)中選出與之相關(guān)的部門數(shù)據(jù),并顯示出來(lái),這似乎也不無(wú)可行。但有經(jīng)驗(yàn)的開發(fā)者就會(huì)發(fā)現(xiàn),由于Web頁(yè)面的無(wú)狀態(tài)性,當(dāng)你再次連接數(shù)據(jù)庫(kù)時(shí),Web頁(yè)面必須得再次刷新。這是一個(gè)頭疼的問題,一方面我們想連接數(shù)據(jù)庫(kù),可另一方面我們必須得保持用戶已輸入數(shù)據(jù)不被破壞。即使如此,估計(jì)用戶也并不希望看到一個(gè)每次選擇都刷新一次的局面。難道就沒有更好的辦法? 有,那就是利用JavaScript的多維數(shù)組。我們?yōu)槭裁床豢梢园研枰@示的數(shù)據(jù)在第一次連接數(shù)據(jù)庫(kù)時(shí)全取出來(lái),放到數(shù)組中去?這樣在每次改變菜單數(shù)據(jù)時(shí),只要從數(shù)組中取得數(shù)據(jù),不就可以大大的提高效率了嗎?這是個(gè)令人振奮的方法,這個(gè)方法中提到的JavaScript數(shù)組,我們暫且稱之為菜單數(shù)據(jù)的容器。 您的思路是不是一下子豁然開朗?可是躍躍欲試一番以后,是不是感到事情好像并不是那么簡(jiǎn)單?問題又來(lái)了,容器的結(jié)構(gòu)該如何設(shè)計(jì),數(shù)據(jù)之間的關(guān)聯(lián)又如何實(shí)現(xiàn)呢?別急,其實(shí)這正是問題之所在。
三、數(shù)據(jù)容器結(jié)構(gòu)的設(shè)計(jì)
說(shuō)起容器結(jié)構(gòu)的設(shè)計(jì),我們得感謝數(shù)據(jù)結(jié)構(gòu)中的鏈表給我們的啟示--鏈表是通過(guò)指針聯(lián)系在一起的。雖然JavaScript中沒有指針的概念,但我們?yōu)槭裁床豢梢阅M一下。 為了討論方便,我們假定數(shù)據(jù)庫(kù)的結(jié)構(gòu)如下:
1、 單位信息表:(unit_id, unit_name, …) 2、 部門信息表:(dept_id, unit_id, dept_name, …) 3、 員工信息表:(emp_id, dept_id, emp_name, …)
利用這個(gè)數(shù)據(jù)庫(kù)結(jié)構(gòu),我們可以很容易的推導(dǎo)出數(shù)組的結(jié)構(gòu)。您說(shuō)的沒錯(cuò),這應(yīng)該是一個(gè)多維數(shù)組。其定義方法應(yīng)該象下面這樣(以部門為例):
var arrDept = new Array(); arrDept[0] = new Array(unit_id0, dept_id0 dept_name0); arrDept[1] = new Array(unit_id1, dept_id1, dept_name1); … arrDept[n] = new Array(unit_idn, dept_idn, dept_namen);
n的大小視實(shí)際數(shù)據(jù)量而定,例如在單位下拉菜單中,n代表單位的總數(shù)。但讀者必須明白,正是由于n的不確定性,以上的代碼必須通過(guò)程序動(dòng)態(tài)的產(chǎn)生。例如對(duì)于ASP程序,我們可以在<script></script>之間嵌入這樣的一段代碼:
<% Dim rs, i '[連接數(shù)據(jù)庫(kù),取出數(shù)據(jù)] response.write "var arrDept = new Array();" & vbNewLine i = 0 while not rs.EOF response.write "arrDept[" & i & "] = new Array('" & rs(unit_id) & "', '" & _ rs(dept_id) & "', '" & rs(dept_name) & "');" & vbNewLine rs.MoveNext i = i +1 wend … %>
代碼拷貝框
[Ctrl+A 全部選擇 然后拷貝]
以上這段代碼用來(lái)從部門表中取出數(shù)據(jù),并產(chǎn)生相關(guān)的JavaScript多維數(shù)組。這只是筆者的一種演示,讀者完全可以使用更靈活的方法來(lái)提取數(shù)據(jù)。 說(shuō)來(lái)說(shuō)去,我們還是要回到JavaScript數(shù)組的結(jié)構(gòu)定義上來(lái)。聰明的讀者應(yīng)該已經(jīng)從上述的代碼中發(fā)現(xiàn)了數(shù)組的定義方法,但筆者還是要不厭其煩的再補(bǔ)充一遍: 我們把數(shù)組的第一個(gè)元素定義為指針,用來(lái)指向其"父結(jié)點(diǎn)"。等等,什么是父結(jié)點(diǎn)?父結(jié)點(diǎn)說(shuō)明白了就是上一級(jí)結(jié)點(diǎn),例如,部門的上一級(jí)是單位,員工的上一級(jí)是部門。那么第二個(gè)元素是什么?讓我們來(lái)看一下下面的一段<SELECT>定義:
<SELECT NAME="s1" onChange=" SetSubMenu(this)"> <OPTION Value="1">單位1</OPTION> <OPTION Value="2">單位2</OPTION> …. </SELECT>
<OPTION>元素的Value屬性從哪里來(lái)呢?對(duì),就是第二個(gè)元素,依此類推,第三個(gè)元素指的就是顯示在菜單中的數(shù)據(jù)嘍,即上面的"單位1"、"單位2"…
讀者到這里可能有些糊涂了,說(shuō)這么多,這個(gè)數(shù)組到底是什么樣?別急,讓我們以部門為例,給出一段根據(jù)部門庫(kù)中的數(shù)據(jù)動(dòng)態(tài)生成的數(shù)組模擬代碼:
<SCRIPT LANGUAGE="JAVASCRIPT"> <!- … var arrDept = new Array(); arrDept[0] = new Array('u01', 'd01', '部門1'); arrDept[1] = new Array('u01', 'd02', '部門2'); … arrDept[8] = new Array('u06', 'd08', '部門8'); … arrDept[15] = new Array('u08', 'd15', '部門15'); … -> </SCRIPT>
數(shù)組終于真相大白。以"u"開頭數(shù)據(jù)的代表單位的編號(hào),即,指向單位的指針,也就是說(shuō),我們可以通過(guò)這個(gè)編號(hào)來(lái)確定該單位所屬的部門;以"d"開頭的數(shù)據(jù)代表部門的編號(hào),用來(lái)供下一級(jí)選單(即員工選單)的指針使用。(注:實(shí)際使用中,數(shù)據(jù)格式根據(jù)情況而定) 有一個(gè)問題,象單位這樣沒有父結(jié)點(diǎn)的數(shù)組該如何定義?很簡(jiǎn)單,把數(shù)組的第一個(gè)元素全部置為0就行了。 下一步,是到我們編寫JavaScript代碼來(lái)控制菜單的顯示的時(shí)候了。我們就假定您生成的三個(gè)數(shù)組分別命名為arrUnit,arrDept,arrEmp。
出處:藍(lán)色理想
責(zé)任編輯:moby
上一頁(yè) 下一頁(yè) web關(guān)聯(lián)菜單實(shí)現(xiàn)方法 [2]
◎進(jìn)入論壇網(wǎng)絡(luò)編程版塊參加討論
|