另外发现有人说用树的方式会更灵活和方便,如图
花了半天时间实现一个多级联动下拉框,目的是对某一植物进行“门纲目科属”的归类。使用的技术是javascript+xml,之所以不用数据库,一来这 方面的数据虽然量大但都是固定不变的,二来不希望加重服务器的负担,第三是因为这种多级从属关系的数据不太适合放在数据库里。
这是大概的思路:
1、读取xml文件
2、当一个下拉框选中某选项时,根据该选项,当前节点指向下一层,进入下一层下拉框的设置
3、取消当前下拉框的禁用,禁用下一层的下拉框
4、清空当前下拉框的选项
5、根据当前节点读取xml的数据,设置下拉框选项
6、返回步骤2
代码:
JavaScript
1. var
2. var
3. var currentNode; //当前所在节点
4.
5. setBrowserType();
6. "classify.xml"
7.
8. //读取xml文件数据并设置门、纲、目、科、属的下拉框
9.
10. //设置“门”的下拉框
11. function
12. currentNode=xmlDoc.documentElement;
13. var
14. var
15. if (browserType== "IE"
16. for ( var
17. //从门到属,都有name属性标签,并且所有下拉框选项索引都是从1开始
18. "name"
19. new
20. }
21. }
22. else { //FF
23. //FireFox没有selectNodes()方法,且其childNodes的对应索引是1,3,5,7...
24. for ( var
25. phylumName=phylums[i].childNodes[1].textContent;
26. new
27. }
28. "disabled"
29. "disabled"
30. "disabled"
31. "disabled"
32. }
33. }
34.
35. //设置“纲”的下拉框
36. function
37. //取消下拉框的禁用
38. //后面的下拉框禁用,这是因应各下拉框的无序选择可能产生的错误
39. //比如选了“科”又回头重新选“目”,或更改同一个下拉框选项)
40. null
41. "disabled"
42. "disabled"
43. "disabled"
44.
45. clearOption(document.forms[0].clazz);
46. var
47. var
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
58. "name"
59. new
60. }
61. }
62. else { //FF
63. currentNode=xmlDoc.documentElement.childNodes[selectedIndex*2-1];
64. clazzes=currentNode.childNodes;
65. for ( var
66. clazzName=clazzes[i+2].childNodes[1].textContent;
67. new
68. }
69. }
70.
71.
72. }
73.
74. //设置“目”的下拉框
75. function
76. //取消下拉框的禁用
77. //后面的下拉框禁用,这是因应各下拉框的无序选择可能产生的错误(比如选了“科”又回头重新选“目”)
78. null
79. "disabled"
80. "disabled"
81.
82. clearOption(document.forms[0].order);
83. var
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
91. for ( var
92. "name"
93. new
94. }
95. else
96. currentNode=xmlDoc.documentElement
97. .childNodes[phylumSI*2-1]
98. .childNodes[selectedIndex*2+1];
99. var
100. for ( var
101. orderName=orders[i+2].childNodes[1].textContent;
102. new
103. }
104. }
105. }
106.
107. //设置“科”的下拉框
108. function
109. null ; //取消下拉框的禁用
110. "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
117. var
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
125. "name"
126. new
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
136. familyName=families[i+2].childNodes[1].textContent;
137. new
138. }
139. }
140. }
141.
142. //设置“属”的下拉框
143. function
144. 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
152. var
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
163. //属为叶节点
164. var
165. new
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
176. //属为叶节点
177. var
178. new
179. }
180. }
181. }
182.
183. //清空下拉框选项
184. function
185. for ( var
186. null
187. }
188. }
189.
190. //判断浏览器类型
191. function
192. if (window.ActiveXObject){ //IE
193. "IE"
194. else
195. "FireFox"
196. }
197. }
198.
199. //载入xml
200. function
201. if (browserType== "IE" ){ //IE
202. new ActiveXObject( "Microsoft.XMLDOM"
203. false
204. xmlDoc.load(xmlName);
205. else
206. // xmlDoc=document.implementation.createDocument("", "", null);
207. // xmlDoc.async = false;
208. // xmlDoc.load("classify.xml");
209. "FireFox"
210. var xmlHttp = new
211. "GET" , "classify.xml" , false
212. 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文件的内容
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]。