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

系统 1322 0

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

 

 

花了半天时间实现一个多级联动下拉框,目的是对某一植物进行“门纲目科属”的归类。使用的技术是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]。

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


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论