另外發現有人說用樹的方式會更靈活和方便,如圖
?
?
花了半天時間實現一個多級聯動下拉框,目的是對某一植物進行“門綱目科屬”的歸類。使用的技術是javascript+xml,之所以不用數據庫,一來這 方面的數據雖然量大但都是固定不變的,二來不希望加重服務器的負擔,第三是因為這種多級從屬關系的數據不太適合放在數據庫里。
這是大概的思路:
1、讀取xml文件
2、當一個下拉框選中某選項時,根據該選項,當前節點指向下一層,進入下一層下拉框的設置
3、取消當前下拉框的禁用,禁用下一層的下拉框
4、清空當前下拉框的選項
5、根據當前節點讀取xml的數據,設置下拉框選項
6、返回步驟2
代碼:
JavaScript
- var ?xmlDoc;????
- var ?browserType;??
- var ?currentNode; //當前所在節點 ??
- ??
- setBrowserType();??
- loadXml( "classify.xml" );??
- ??
- //讀取xml文件數據并設置門、綱、目、科、屬的下拉框 ??
- ??
- //設置“門”的下拉框 ??
- function ?setPhylum(){??
- ????currentNode=xmlDoc.documentElement;??
- ???? var ?phylums=xmlDoc.documentElement.childNodes;??
- ???? var ?phylumName;??
- ???? if (browserType== "IE" ){??
- ???????? for ( var ?i=0;i<phylums.length;i++){??
- ???????????? //從門到屬,都有name屬性標簽,并且所有下拉框選項索引都是從1開始 ??
- ????????????phylumName=phylums[i].selectNodes( "name" )[0].text;??
- ????????????document.forms[0].phylum.options[i+1]= new ?Option(phylumName,phylumName);??
- ????????}??
- ????}??
- ???? else { //FF ??
- ???????? //FireFox沒有selectNodes()方法,且其childNodes的對應索引是1,3,5,7... ??
- ???????? for ( var ?i=1;i<phylums.length;i=i+2){??
- ????????????phylumName=phylums[i].childNodes[1].textContent;??
- ????????????document.forms[0].phylum.options[(i+1)/2]= new ?Option(phylumName,phylumName);??
- ????????}??
- ????????document.forms[0].clazz.disabled= "disabled" ;??
- ????????document.forms[0].order.disabled= "disabled" ;??
- ????????document.forms[0].family.disabled= "disabled" ;??
- ????????document.forms[0].genus.disabled= "disabled" ;??
- ????}??
- }??
- ??
- //設置“綱”的下拉框 ??
- function ?setClazz(selectedIndex){??
- ???? //取消下拉框的禁用 ??
- ???? //后面的下拉框禁用,這是因應各下拉框的無序選擇可能產生的錯誤 ??
- ???? //比如選了“科”又回頭重新選“目”,或更改同一個下拉框選項) ??
- ????document.forms[0].clazz.disabled= null ;??
- ????document.forms[0].order.disabled= "disabled" ;??
- ????document.forms[0].family.disabled= "disabled" ;??
- ????document.forms[0].genus.disabled= "disabled" ;??
- ??????
- ????clearOption(document.forms[0].clazz);??
- ???? var ?clazzes;??
- ???? var ?clazzName;??
- ???? //將選中的門節點作為當前節點,注意這里需要將索引回減1 ??
- ???? //因為門的父節點沒有name屬性標簽,而下拉框的索引又是從1開始 ??
- ???? //currentNode的賦值應使用絕對定位,也是因應各下拉框的無序選擇 ??
- ???? //currentNode=currentNode.childNodes(selectedIndex-1); ??
- ???? if (browserType== "IE" ){??
- ????????currentNode=xmlDoc.documentElement.childNodes(selectedIndex-1);??
- ????????clazzes=currentNode.childNodes;??
- ???????? //因為門節點的第一個子節點為name屬性標簽,故循環時索引從1開始 ??
- ???????? //相應的下拉框的索引就與綱節點的索引同步(不需要options[i+1]),目、科、屬也是一樣 ??
- ???????? for ( var ?i=1;i<clazzes.length;i++){??
- ????????????clazzName=clazzes[i].selectNodes( "name" )[0].text;??
- ????????????document.forms[0].clazz.options[i]= new ?Option(clazzName,clazzName);??
- ????????}??
- ????}??
- ???? else { //FF ??
- ????????currentNode=xmlDoc.documentElement.childNodes[selectedIndex*2-1];??
- ????????clazzes=currentNode.childNodes;??
- ???????? for ( var ?i=1;i<clazzes.length-2;i=i+2){??
- ????????????clazzName=clazzes[i+2].childNodes[1].textContent;??
- ????????????document.forms[0].clazz.options[(i+1)/2]= new ?Option(clazzName,clazzName);??
- ????????}??
- ????}??
- ??????
- ??????
- }??
- ??
- //設置“目”的下拉框 ??
- function ?setOrder(selectedIndex){??
- ???? //取消下拉框的禁用 ??
- ???? //后面的下拉框禁用,這是因應各下拉框的無序選擇可能產生的錯誤(比如選了“科”又回頭重新選“目”) ??
- ????document.forms[0].order.disabled= null ;??
- ????document.forms[0].family.disabled= "disabled" ;??
- ????document.forms[0].genus.disabled= "disabled" ;??
- ??????
- ????clearOption(document.forms[0].order);??
- ???? var ?orderName;??
- ???? //currentNode的賦值應使用絕對定位 ??
- ???? var ?phylumSI=document.forms[0].phylum.selectedIndex;???? //phylum?selected?index ??
- ???? if (browserType== "IE" ){??
- ????????currentNode=xmlDoc.documentElement??
- ????????????.childNodes[phylumSI-1]??
- ????????????.childNodes[selectedIndex];??
- ???????? var ?orders=currentNode.childNodes;??
- ???????? for ( var ?i=1;i<orders.length;i++){??
- ????????????orderName=orders[i].selectNodes( "name" )[0].text;??
- ????????????document.forms[0].order.options[i]= new ?Option(orderName,orderName);??
- ????????}??
- ????} else {??
- ????????currentNode=xmlDoc.documentElement??
- ????????????.childNodes[phylumSI*2-1]??
- ????????????.childNodes[selectedIndex*2+1];??
- ???????? var ?orders=currentNode.childNodes;??
- ???????? for ( var ?i=1;i<orders.length-2;i=i+2){??
- ????????????orderName=orders[i+2].childNodes[1].textContent;??
- ????????????document.forms[0].order.options[(i+1)/2]= new ?Option(orderName,orderName);??
- ????????}??
- ????}??
- }??
- ??
- //設置“科”的下拉框 ??
- function ?setFamily(selectedIndex){??
- ????document.forms[0].family.disabled= null ; //取消下拉框的禁用 ??
- ????document.forms[0].genus.disabled= "disabled" ; //后面的下拉框禁用 ??
- ??????
- ???? //currentNode的賦值應使用絕對定位 ??
- ???? var ?phylumSI=document.forms[0].phylum.selectedIndex; //phylum?selected?index ??
- ???? var ?clazzSI=document.forms[0].clazz.selectedIndex;?? //clazz?selected?index ??
- ????clearOption(document.forms[0].family);??
- ???? var ?families;??
- ???? var ?familyName;??
- ???? if (browserType== "IE" ){??
- ????????currentNode=xmlDoc.documentElement??
- ????????????.childNodes[phylumSI-1]??
- ????????????.childNodes[clazzSI]??
- ????????????.childNodes[selectedIndex];??
- ????????families=currentNode.childNodes;??
- ???????? for ( var ?i=1;i<families.length;i++){??
- ????????????familyName=families[i].selectNodes( "name" )[0].text;??
- ????????????document.forms[0].family.options[i]= new ?Option(familyName,familyName);??
- ????????}??
- ????}??
- ???? else {??
- ????????currentNode=xmlDoc.documentElement??
- ????????????.childNodes[phylumSI*2-1]??
- ????????????.childNodes[clazzSI*2+1]??
- ????????????.childNodes[selectedIndex*2+1];??
- ????????families=currentNode.childNodes;??
- ???????? for ( var ?i=1;i<families.length-2;i=i+2){??
- ????????????familyName=families[i+2].childNodes[1].textContent;??
- ????????????document.forms[0].family.options[(i+1)/2]= new ?Option(familyName,familyName);??
- ????????}??
- ????}??
- }??
- ??
- //設置“屬”的下拉框 ??
- function ?setGenus(selectedIndex){??
- ????document.forms[0].genus.disabled= null ; //取消下拉框的禁用 ??
- ??????
- ???? //currentNode的賦值應使用絕對定位 ??
- ???? var ?phylumSI=document.forms[0].phylum.selectedIndex; //phylum?selected?index ??
- ???? var ?clazzSI=document.forms[0].clazz.selectedIndex;?? //clazz?selected?index ??
- ???? var ?orderSI=document.forms[0].order.selectedIndex;?? //order?selected?index ??
- ????clearOption(document.forms[0].genus);??
- ???? var ?genues;??
- ???? var ?genusName;??
- ??????
- ???? if (browserType== "IE" ){??
- ??????????
- ????????currentNode=xmlDoc.documentElement??
- ????????????.childNodes(phylumSI-1)??
- ????????????.childNodes(clazzSI)??
- ????????????.childNodes(orderSI)??
- ????????????.childNodes(selectedIndex);??
- ????????genuses=currentNode.childNodes;??
- ???????? for ( var ?i=1;i<genuses.length;i++){??
- ???????????? //屬為葉節點 ??
- ???????????? var ?genusName=genuses[i].text;??
- ????????????document.forms[0].genus.options[i]= new ?Option(genusName,genusName);??
- ????????}??
- ????}??
- ???? else {??
- ????????currentNode=xmlDoc.documentElement??
- ????????????.childNodes[phylumSI*2-1]??
- ????????????.childNodes[clazzSI*2+1]??
- ????????????.childNodes[orderSI*2+1]??
- ????????????.childNodes[selectedIndex*2+1];??
- ????????genuses=currentNode.childNodes;??
- ???????? for ( var ?i=1;i<genuses.length-2;i=i+2){??
- ???????????? //屬為葉節點 ??
- ???????????? var ?genusName=genuses[i+2].textContent;??
- ????????????document.forms[0].genus.options[(i+1)/2]= new ?Option(genusName,genusName);??
- ????????}??
- ????}??
- }??
- ??
- //清空下拉框選項 ??
- function ?clearOption(selectElement){??
- ???? for ( var ?i=1;i<selectElement.options.length;i++){??
- ????????selectElement.options[i]= null ;??
- ????}??
- }??
- ??
- //判斷瀏覽器類型 ??
- function ?setBrowserType(){??
- ???? if ?(window.ActiveXObject){ //IE ??
- ????????browserType= "IE" ;??
- ????} else {??
- ????????browserType= "FireFox" ;??
- ????}??
- }??
- ??
- //載入xml ??
- function ?loadXml(xmlName){??
- ???? if ?(browserType== "IE" ){ //IE ??
- ????????xmlDoc?=? new ?ActiveXObject( "Microsoft.XMLDOM" );???
- ????????xmlDoc.async?=? false ;??
- ????????xmlDoc.load(xmlName);??
- ????}? else {??
- //??????xmlDoc=document.implementation.createDocument("",?"",?null); ??
- //??????xmlDoc.async?=?false; ??
- //??????xmlDoc.load("classify.xml"); ??
- ????????browserType= "FireFox" ;??
- ???????? var ?xmlHttp?=? new ?XMLHttpRequest();??
- ????????xmlHttp.open(? "GET" ,? "classify.xml" ,? false ?)?;??
- ????????xmlHttp.send( null )?;??
- ????????xmlDoc=xmlHttp.responseXML;??
- ??????????
- ???????? //FireFox沒有selectNodes()方法,且xml中,其childNodes的對應索引是1,3,5,7... ??
- //??????alert(xmlDoc.getElementsByTagName("phylum")[1] ??
- //??????????.childNodes[3].childNodes[3].childNodes[1].textContent); ??
- ????}??
- }??
最后是xml文件的內容
- <? xml ? version = "1.0" ? encoding = "UTF-8" ?> ??
- < plant > ??
- ???? < phylum > ??
- ???????? < name > 被子植物門 </ name > ??
- ???????? < clazz > ??
- ???????????? < name > 雙子葉植物綱 </ name > ??
- ???????????? < order > ??
- ???????????????? < name > 菊目 </ name > ??
- ???????????????? < family > ??
- ???????????????????? < name > 菊科 </ name > ??
- ???????????????????? < genus > 菊屬 </ genus > ??
- ???????????????? </ family > ??
- ???????????????? < family > ??
- ???????????????????? < name > 桔梗科 </ name > ??
- ???????????????????? < genus > 同鐘花屬 </ genus > ??
- ???????????????????? < genus > 刺萼參屬 </ genus > ??
- ???????????????? </ family > ??
- ???????????? </ order > ??
- ???????????? < order > ??
- ???????????????? < name > 胡椒目 </ name > ??
- ???????????????? < family > ??
- ???????????????????? < name > 胡椒科 </ name > ??
- ???????????????????? < genus > 胡椒屬 </ genus > ??
- ???????????????????? < genus > 草胡椒屬 </ genus > ??
- ???????????????????? < genus > 齊頭絨屬 </ genus > ??
- ???????????????? </ family > ??
- ???????????? </ order > ??
- ???????? </ clazz > ??
- ???? </ phylum > ??
- ???? < phylum > ??
- ???????? < name > 蕨類植物門 </ name > ??
- ???????? < clazz > ??
- ???????????? < name > 石松綱 </ name > ??
- ???????????? < order > ??
- ???????????????? < name > 石松目 </ name > ??
- ???????????????? < family > ??
- ???????????????????? < name > 石松科 </ name > ??
- ???????????????????? < genus > 石松屬 </ genus > ??
- ???????????????? </ family > ??
- ???????????? </ order > ??
- ???????? </ clazz > ??
- ???? </ phylum > ??
- </ plant > ??
這是部分效果圖:
可以實現上下級下拉框的聯動,支持無序選擇,若向上重新選擇,下下層下拉框將自動被禁用,下層下拉框選項也會相應改變。
有一點不足是,因為數據量實在太大,這樣5個下拉框仍然可能出現某下拉框有幾百甚至幾千個選項,此時就失去了下拉框的意義,因此正在考慮是否應該做成輸入框的形式,或者像搜索引擎那樣帶有輸入提示功能,研究中,歡迎拍磚。
PS:重新修改了一下,可以支持FireFox了,這可真是麻煩的工程:FireFox的JavaScript的Element對象中沒有 selectNodes()方法,只有調用childNodes()或者getElementsByTagName();并且在FireFox中,xml 中節點對應childNodes()的索引是1,3,5,7...,也就是說,如果你想讀取xml某個節點下的第i個子節點,正常我們就會寫 someNode.childNodes[i-1],但在FireFox就必須寫作someNode.childNodes[i*2-1]。
另外在使用數組時,IE允許把小括號當成中括號使用(即someArray[i]和someArray(i)均合法),FireFox則不行,所以最好統一寫someArray[i]。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
