`

js实现xml的多级联动下拉框

阅读更多

另外发现有人说用树的方式会更灵活和方便,如图

 

 

花了半天时间实现一个多级联动下拉框,目的是对某一植物进行“门纲目科属”的归类。使用的技术是javascript+xml,之所以不用数据库,一来这 方面的数据虽然量大但都是固定不变的,二来不希望加重服务器的负担,第三是因为这种多级从属关系的数据不太适合放在数据库里。

这是大概的思路:
1、读取xml文件
2、当一个下拉框选中某选项时,根据该选项,当前节点指向下一层,进入下一层下拉框的设置
3、取消当前下拉框的禁用,禁用下一层的下拉框
4、清空当前下拉框的选项
5、根据当前节点读取xml的数据,设置下拉框选项
6、返回步骤2

代码:
JavaScript

Javascript代码  收藏代码
  1. var  xmlDoc;    
  2. var  browserType;  
  3. var  currentNode; //当前所在节点   
  4.   
  5. setBrowserType();  
  6. loadXml("classify.xml" );  
  7.   
  8. //读取xml文件数据并设置门、纲、目、科、属的下拉框   
  9.   
  10. //设置“门”的下拉框   
  11. function  setPhylum(){  
  12.     currentNode=xmlDoc.documentElement;  
  13.     var  phylums=xmlDoc.documentElement.childNodes;  
  14.     var  phylumName;  
  15.     if (browserType== "IE" ){  
  16.         for ( var  i=0;i<phylums.length;i++){  
  17.             //从门到属,都有name属性标签,并且所有下拉框选项索引都是从1开始   
  18.             phylumName=phylums[i].selectNodes("name" )[0].text;  
  19.             document.forms[0].phylum.options[i+1]=new  Option(phylumName,phylumName);  
  20.         }  
  21.     }  
  22.     else { //FF   
  23.         //FireFox没有selectNodes()方法,且其childNodes的对应索引是1,3,5,7...   
  24.         for ( var  i=1;i<phylums.length;i=i+2){  
  25.             phylumName=phylums[i].childNodes[1].textContent;  
  26.             document.forms[0].phylum.options[(i+1)/2]=new  Option(phylumName,phylumName);  
  27.         }  
  28.         document.forms[0].clazz.disabled="disabled" ;  
  29.         document.forms[0].order.disabled="disabled" ;  
  30.         document.forms[0].family.disabled="disabled" ;  
  31.         document.forms[0].genus.disabled="disabled" ;  
  32.     }  
  33. }  
  34.   
  35. //设置“纲”的下拉框   
  36. function  setClazz(selectedIndex){  
  37.     //取消下拉框的禁用   
  38.     //后面的下拉框禁用,这是因应各下拉框的无序选择可能产生的错误   
  39.     //比如选了“科”又回头重新选“目”,或更改同一个下拉框选项)   
  40.     document.forms[0].clazz.disabled=null ;  
  41.     document.forms[0].order.disabled="disabled" ;  
  42.     document.forms[0].family.disabled="disabled" ;  
  43.     document.forms[0].genus.disabled="disabled" ;  
  44.       
  45.     clearOption(document.forms[0].clazz);  
  46.     var  clazzes;  
  47.     var  clazzName;  
  48.     //将选中的门节点作为当前节点,注意这里需要将索引回减1   
  49.     //因为门的父节点没有name属性标签,而下拉框的索引又是从1开始   
  50.     //currentNode的赋值应使用绝对定位,也是因应各下拉框的无序选择   
  51.     //currentNode=currentNode.childNodes(selectedIndex-1);   
  52.     if (browserType== "IE" ){  
  53.         currentNode=xmlDoc.documentElement.childNodes(selectedIndex-1);  
  54.         clazzes=currentNode.childNodes;  
  55.         //因为门节点的第一个子节点为name属性标签,故循环时索引从1开始   
  56.         //相应的下拉框的索引就与纲节点的索引同步(不需要options[i+1]),目、科、属也是一样   
  57.         for ( var  i=1;i<clazzes.length;i++){  
  58.             clazzName=clazzes[i].selectNodes("name" )[0].text;  
  59.             document.forms[0].clazz.options[i]=new  Option(clazzName,clazzName);  
  60.         }  
  61.     }  
  62.     else { //FF   
  63.         currentNode=xmlDoc.documentElement.childNodes[selectedIndex*2-1];  
  64.         clazzes=currentNode.childNodes;  
  65.         for ( var  i=1;i<clazzes.length-2;i=i+2){  
  66.             clazzName=clazzes[i+2].childNodes[1].textContent;  
  67.             document.forms[0].clazz.options[(i+1)/2]=new  Option(clazzName,clazzName);  
  68.         }  
  69.     }  
  70.       
  71.       
  72. }  
  73.   
  74. //设置“目”的下拉框   
  75. function  setOrder(selectedIndex){  
  76.     //取消下拉框的禁用   
  77.     //后面的下拉框禁用,这是因应各下拉框的无序选择可能产生的错误(比如选了“科”又回头重新选“目”)   
  78.     document.forms[0].order.disabled=null ;  
  79.     document.forms[0].family.disabled="disabled" ;  
  80.     document.forms[0].genus.disabled="disabled" ;  
  81.       
  82.     clearOption(document.forms[0].order);  
  83.     var  orderName;  
  84.     //currentNode的赋值应使用绝对定位   
  85.     var  phylumSI=document.forms[0].phylum.selectedIndex;     //phylum selected index   
  86.     if (browserType== "IE" ){  
  87.         currentNode=xmlDoc.documentElement  
  88.             .childNodes[phylumSI-1]  
  89.             .childNodes[selectedIndex];  
  90.         var  orders=currentNode.childNodes;  
  91.         for ( var  i=1;i<orders.length;i++){  
  92.             orderName=orders[i].selectNodes("name" )[0].text;  
  93.             document.forms[0].order.options[i]=new  Option(orderName,orderName);  
  94.         }  
  95.     }else {  
  96.         currentNode=xmlDoc.documentElement  
  97.             .childNodes[phylumSI*2-1]  
  98.             .childNodes[selectedIndex*2+1];  
  99.         var  orders=currentNode.childNodes;  
  100.         for ( var  i=1;i<orders.length-2;i=i+2){  
  101.             orderName=orders[i+2].childNodes[1].textContent;  
  102.             document.forms[0].order.options[(i+1)/2]=new  Option(orderName,orderName);  
  103.         }  
  104.     }  
  105. }  
  106.   
  107. //设置“科”的下拉框   
  108. function  setFamily(selectedIndex){  
  109.     document.forms[0].family.disabled=null ; //取消下拉框的禁用   
  110.     document.forms[0].genus.disabled="disabled" ; //后面的下拉框禁用   
  111.       
  112.     //currentNode的赋值应使用绝对定位   
  113.     var  phylumSI=document.forms[0].phylum.selectedIndex; //phylum selected index   
  114.     var  clazzSI=document.forms[0].clazz.selectedIndex;   //clazz selected index   
  115.     clearOption(document.forms[0].family);  
  116.     var  families;  
  117.     var  familyName;  
  118.     if (browserType== "IE" ){  
  119.         currentNode=xmlDoc.documentElement  
  120.             .childNodes[phylumSI-1]  
  121.             .childNodes[clazzSI]  
  122.             .childNodes[selectedIndex];  
  123.         families=currentNode.childNodes;  
  124.         for ( var  i=1;i<families.length;i++){  
  125.             familyName=families[i].selectNodes("name" )[0].text;  
  126.             document.forms[0].family.options[i]=new  Option(familyName,familyName);  
  127.         }  
  128.     }  
  129.     else {  
  130.         currentNode=xmlDoc.documentElement  
  131.             .childNodes[phylumSI*2-1]  
  132.             .childNodes[clazzSI*2+1]  
  133.             .childNodes[selectedIndex*2+1];  
  134.         families=currentNode.childNodes;  
  135.         for ( var  i=1;i<families.length-2;i=i+2){  
  136.             familyName=families[i+2].childNodes[1].textContent;  
  137.             document.forms[0].family.options[(i+1)/2]=new  Option(familyName,familyName);  
  138.         }  
  139.     }  
  140. }  
  141.   
  142. //设置“属”的下拉框   
  143. function  setGenus(selectedIndex){  
  144.     document.forms[0].genus.disabled=null ; //取消下拉框的禁用   
  145.       
  146.     //currentNode的赋值应使用绝对定位   
  147.     var  phylumSI=document.forms[0].phylum.selectedIndex; //phylum selected index   
  148.     var  clazzSI=document.forms[0].clazz.selectedIndex;   //clazz selected index   
  149.     var  orderSI=document.forms[0].order.selectedIndex;   //order selected index   
  150.     clearOption(document.forms[0].genus);  
  151.     var  genues;  
  152.     var  genusName;  
  153.       
  154.     if (browserType== "IE" ){  
  155.           
  156.         currentNode=xmlDoc.documentElement  
  157.             .childNodes(phylumSI-1)  
  158.             .childNodes(clazzSI)  
  159.             .childNodes(orderSI)  
  160.             .childNodes(selectedIndex);  
  161.         genuses=currentNode.childNodes;  
  162.         for ( var  i=1;i<genuses.length;i++){  
  163.             //属为叶节点   
  164.             var  genusName=genuses[i].text;  
  165.             document.forms[0].genus.options[i]=new  Option(genusName,genusName);  
  166.         }  
  167.     }  
  168.     else {  
  169.         currentNode=xmlDoc.documentElement  
  170.             .childNodes[phylumSI*2-1]  
  171.             .childNodes[clazzSI*2+1]  
  172.             .childNodes[orderSI*2+1]  
  173.             .childNodes[selectedIndex*2+1];  
  174.         genuses=currentNode.childNodes;  
  175.         for ( var  i=1;i<genuses.length-2;i=i+2){  
  176.             //属为叶节点   
  177.             var  genusName=genuses[i+2].textContent;  
  178.             document.forms[0].genus.options[(i+1)/2]=new  Option(genusName,genusName);  
  179.         }  
  180.     }  
  181. }  
  182.   
  183. //清空下拉框选项   
  184. function  clearOption(selectElement){  
  185.     for ( var  i=1;i<selectElement.options.length;i++){  
  186.         selectElement.options[i]=null ;  
  187.     }  
  188. }  
  189.   
  190. //判断浏览器类型   
  191. function  setBrowserType(){  
  192.     if  (window.ActiveXObject){ //IE   
  193.         browserType="IE" ;  
  194.     }else {  
  195.         browserType="FireFox" ;  
  196.     }  
  197. }  
  198.   
  199. //载入xml   
  200. function  loadXml(xmlName){  
  201.     if  (browserType== "IE" ){ //IE   
  202.         xmlDoc = new  ActiveXObject( "Microsoft.XMLDOM" );   
  203.         xmlDoc.async = false ;  
  204.         xmlDoc.load(xmlName);  
  205.     } else {  
  206. //      xmlDoc=document.implementation.createDocument("", "", null);   
  207. //      xmlDoc.async = false;   
  208. //      xmlDoc.load("classify.xml");   
  209.         browserType="FireFox" ;  
  210.         var  xmlHttp =  new  XMLHttpRequest();  
  211.         xmlHttp.open( "GET" "classify.xml" false  ) ;  
  212.         xmlHttp.send(null ) ;  
  213.         xmlDoc=xmlHttp.responseXML;  
  214.           
  215.         //FireFox没有selectNodes()方法,且xml中,其childNodes的对应索引是1,3,5,7...   
  216. //      alert(xmlDoc.getElementsByTagName("phylum")[1]   
  217. //          .childNodes[3].childNodes[3].childNodes[1].textContent);   
  218.     }  
  219. }  




最后是xml文件的内容

Xml代码  收藏代码
  1. <? xml   version = "1.0"   encoding = "UTF-8" ?>   
  2. < plant >   
  3.     < phylum >   
  4.         < name > 被子植物门 </ name >   
  5.         < clazz >   
  6.             < name > 双子叶植物纲 </ name >   
  7.             < order >   
  8.                 < name > 菊目 </ name >   
  9.                 < family >   
  10.                     < name > 菊科 </ name >   
  11.                     < genus > 菊属 </ genus >   
  12.                 </ family >   
  13.                 < family >   
  14.                     < name > 桔梗科 </ name >   
  15.                     < genus > 同钟花属 </ genus >   
  16.                     < genus > 刺萼参属 </ genus >   
  17.                 </ family >   
  18.             </ order >   
  19.             < order >   
  20.                 < name > 胡椒目 </ name >   
  21.                 < family >   
  22.                     < name > 胡椒科 </ name >   
  23.                     < genus > 胡椒属 </ genus >   
  24.                     < genus > 草胡椒属 </ genus >   
  25.                     < genus > 齐头绒属 </ genus >   
  26.                 </ family >   
  27.             </ order >   
  28.         </ clazz >   
  29.     </ phylum >   
  30.     < phylum >   
  31.         < name > 蕨类植物门 </ name >   
  32.         < clazz >   
  33.             < name > 石松纲 </ name >   
  34.             < order >   
  35.                 < name > 石松目 </ name >   
  36.                 < family >   
  37.                     < name > 石松科 </ name >   
  38.                     < genus > 石松属 </ genus >   
  39.                 </ family >   
  40.             </ order >   
  41.         </ clazz >   
  42.     </ phylum >   
  43. </ 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]。

  • 大小: 16.3 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics