cuiyi's blog(崔毅 crazycy)

记录点滴 鉴往事之得失 以资于发展
数据加载中……

ajax巨好用,4级级联菜单的解决

为解决省、市、区、区域4级级联菜单,在网上搜索了大量的级联菜单解决方案,也请教过不少朋友,要么过于复杂,要么过于占内存,未果。

在建议下,悉心读《ajax基础教程》4余遍,方有与ajax相识恨晚之感,唯一的感慨就是好用好用绝对好用。

现在把已经可以正常运行的例子的核心代码分享:
客户端ajax代码如下:
<script type="text/javascript">
        var xmlHttp;
        var domainId;
        var type;
        
        function refreshList(typesource) {
            createXMLHttpRequest();
            type 
= typesource;
            
if ("p" == type) {
                getSelectedId(
"province_select");
            } 
else if("c" == type) {
                getSelectedId(
"city_select");
            } 
else if("s" == type) {
                getSelectedId(
"section_select");
            } 
            var url 
= "enterpriseManage2.html?method=retrieve&ts=" + new Date().getTime();
            var queryStr 
= "domainId=" + domainId;
            alert(queryStr);
            xmlHttp.onreadystatechange
=handleStateChange;
            xmlHttp.open(
"POST", url);
            xmlHttp.setRequestHeader(
"Content-Type","application/x-www-form-urlencoded;");
            xmlHttp.send(queryStr);
        }
        
        function handleStateChange() {
            
if (xmlHttp.readyState == 4) {
                
if (xmlHttp.status == 200) {
                    updateList();
                }
            }
         }
         
         function getSelectedId(elementId) {
             alert(
"elementId: " + elementId);
             
//var selectedId = null;
             var options = document.getElementById(elementId).childNodes;
             var option 
= null;
             
for (var i = 0, n = options.length; i < n; i++) {
                 option 
= options[i];
                 
if (option.selected) {
                     domainId 
= option.value;
                     
//return selectedId;
                 }
             }
         }
         
         function updateList() {
             alert(
"type: " + type);
             
if ("p" == type) {
                 var select 
= document.getElementById("city_select");
                 var options 
= xmlHttp.responseXML.getElementsByTagName("domain");
                 for (var i = 0, n = options.length; i < n; i++) {
                     select.appendChild(createElementWithValue(options[i]));
                 }
             } 
else if("c" == type) {
                 var select 
= document.getElementById("section_select");
                 var options 
= xmlHttp.responseXML.getElementsByTagName("domain");
                 for (var i = 0, n = options.length; i < n; i++) {
                     select.appendChild(createElementWithValue(options[i]));
                 }    
             } 
else if("s" == type) {
                 var select 
= document.getElementById("appointDomain");
                 var options 
= xmlHttp.responseXML.getElementsByTagName("domain");
                 
for (var i = 0, n = options.length; i < n; i++) {
                     select.appendChild(createElementWithValue(options[i]));
                 }    
             }
         }

         
         function createElementWithValue(text) {
             var element 
= document.createElement("option");
             element.setAttribute(
"value", text.getAttribute("id"));
             var text 
= document.createTextNode(text.firstChild.nodeValue);
             element.appendChild(text);
             
return element;
         }
        
        function createXMLHttpRequest() {
            
if(window.XMLHttpRequest) {
                    xmlHttp = new XMLHttpRequest();
                } 
else if (window.ActiveXObject) {
                    try {
                        xmlHttp 
= new ActiveXObject("Msxml2.XMLHTTP");
                    } 
catch (e) {
                        
try {
                            xmlHttp 
= new ActiveXObject("Microsoft.XMLHTTP");
                        } 
catch (e) {
                        }
                    }
                }
        }

    
</script>


页面调用处代码如下:
<td align="left" class="list_content" width="75%">
    省
   
<select id="province_select" name="province_select" onchange="refreshList('p');"> 
        
<option value="" SELECTED>请选择</option>
            
<%
                java.util.Iterator it 
= ((java.util.List)request.getAttribute("province_options")).iterator();
               
while (it.hasNext()) {
                    Province province 
= (Province)it.next();
             
%>
             
<option value=<%=province.getId()%>><%=province.getName()%></option>
             
<%
                 }
             
%>
   
</select>
    市
   
<select id="city_select" name="city_select" onchange="refreshList('c');">      
         <option value="" SELECTED>请选择</option>
   
</select>
    区
   
<select id="section_select" name="section_select" onchange="refreshList('s');"> 
        
<option value="" SELECTED>请选择</option>
   
</select>
    区域
   
<select id="appointDomain" name="appointDomain"> 
        
<option value="" SELECTED>请选择</option>
   
</select>
</td>


服务器端action(Struts)代码如下:
 1 public ActionForward retrieve(ActionMapping mapping, ActionForm actionForm,
 2             HttpServletRequest request, HttpServletResponse response) {
 3         String domainId = request.getParameter("domainId");
 4         DomainFactory factory = DomainFactory.getInstance();
 5         Object domain = factory.getDomain(domainId);
 6         StringBuffer responseXML = new StringBuffer("<domains>");
 7         if(domain instanceof Province) {
 8             Province province = (Province)domain;
 9             Iterator it = province.getCities().iterator();
10             while (it.hasNext()) {
11                 City city = (City)it.next();
12                 responseXML.append("<domain");
13                 responseXML.append(" id='" + city.getId());
14                 responseXML.append("'>");
15                 responseXML.append(city.getName());
16                 responseXML.append("</domain>");
17             }
18         } else if(domain instanceof City) {
19             City city = (City)domain;
20             Iterator it = city.getSections().iterator();
21             while (it.hasNext()) {
22                 Section section = (Section)it.next();
23                 responseXML.append("<domain");
24                 responseXML.append(" id='" + section.getId());
25                 responseXML.append("'>");
26                 responseXML.append(section.getName());
27                 responseXML.append("</domain>");
28             }
29         } else if (domain instanceof Section) {
30             Section section = (Section)domain;
31             Iterator it = section.getRegions().iterator();
32             while (it.hasNext()) {
33                 Region region = (Region)it.next();
34                 responseXML.append("<domain");
35                 responseXML.append(" id='" + region.getId());
36                 responseXML.append("'>");
37                 responseXML.append(region.getName());
38                 responseXML.append("</domain>");
39             }
40         } 
41         responseXML.append("</domains>");
42         response.setContentType("text/xml");
43         try {
44             PrintWriter out = (PrintWriter)response.getWriter();
45             out.write(responseXML.toString());
46             System.out.println(responseXML.toString());
47             //out.flush();
48         } catch (IOException e) {
49             //do nothing
50             e.printStackTrace();
51         }
52         return null;
53     }


附注:这里用jsp或者servlet都可行。今天还看到一个朋友在dearbook上问某书的示例为啥不用Servlet而用JSP,

问题如下:读第*章,发现XMLHttpRequest.open(method,url,true)中的url请求的都是jsp,然后由jsp再调用处理方法,然后再out.print().不能直接发送请求到servlet让servlet处理再out.print()?疑惑...?

我的观点:
jsp的调用和out打印与servlet本质上是一致的;如果采用servlet从理论上更说得过去,但是对于示例未必最佳,毕竟jsp只要放在web容器的某个应用下就ok;如果是servlet则需要配置;对于一本讲述概要而不是深入讨论最佳实践的书,我觉得作者的不足是没有提到其它可行方案或者解释为啥通过这个方式来示例;对于读者来说,应该产生这个疑问,并且该弄明白为啥这么干

声明:
本例子在firefox下完全正常运行;
在IE下运行到红色标记处得到的对象的个数居然是0;严重疑惑中,希望得到朋友们的指点.....

posted on 2006-07-22 21:32 crazycy 阅读(7388) 评论(14)  编辑  收藏 所属分类: JavaEE技术

评论

# re: ajax巨好用,4级级联菜单的解决  回复  更多评论   

使用DWR实现这个功能会更加方便,但是代码会简洁很多。
2006-07-22 22:06 | Faith.Yan

# re: ajax巨好用,4级级联菜单的解决  回复  更多评论   

DWR?呵呵;好的,再学习一下
2006-07-23 13:20 | crazycy

# re: ajax巨好用,4级级联菜单的解决  回复  更多评论   

检查一下生成的xml有没有问题,我看了两遍,没发现有什么问题,还有就是编码问题,如果服务器端出现编码问题会无法生成xml的。
2006-07-23 19:08 | TiGERTiAN

# re: ajax巨好用,4级级联菜单的解决  回复  更多评论   

@TiGERTiAN
多谢TiGERTiAN

服务端返回了正确的XML格式 我打印检查过了
<domains><domain id='1_beijing'>北京</domain></domains>

而且在Firefox浏览器中是没有问题的....


2006-07-23 20:11 | crazycy

# re: ajax巨好用,4级级联菜单的解决  回复  更多评论   

你可以把你的源程序发给我吗?我来看看
tigertian@gmail.com
2006-07-23 20:20 | TiGERTiAN

# re: ajax巨好用,4级级联菜单的解决  回复  更多评论   

@TiGERTiAN


have send, thanks a lot
2006-07-24 14:07 | crazycy

# re: ajax巨好用,4级级联菜单的解决  回复  更多评论   

@Faith.Yan
@TiGERTiAN
@crazycy
jd
2006-10-09 19:29 | 小鱼

# re: ajax巨好用,4级级联菜单的解决  回复  更多评论   

我是一个初学者,可以把源文件发给我吗?
谢谢
Email:endisoft@gmail.com
2006-10-14 11:23 | Endisoft

# re: ajax巨好用,4级级联菜单的解决  回复  更多评论   

想问一下,IE中对象个数为0的问题解决没有,有的话麻烦说一下解决办法~
另外想认识一下交个朋友
qq:154242387
Email:xz0312-221@163.com
2007-03-19 14:43 | SINO

# re: ajax巨好用,4级级联菜单的解决  回复  更多评论   

@SINO
哈哈,好的,我已经加您了。

至于IE对象个数为0的问题,我并没有处理好,惭愧啊;一起切磋切磋
2007-03-20 23:14 | crazycy

# re: ajax巨好用,4级级联菜单的解决  回复  更多评论   

为0的情况你
servletResponse.setContentType("text/xml;charset=UTF-8");
看看
2007-04-19 11:49 | zhh1981

# re: ajax巨好用,4级级联菜单的解决  回复  更多评论   

给代码不加注释是犯罪行为i
2007-08-29 10:17 | 可ing

# re: ajax巨好用,4级级联菜单的解决[未登录]  回复  更多评论   

是不是具体的省县市的列表还没有呢?
2008-02-19 16:34 | rock

# re: ajax巨好用,4级级联菜单的解决  回复  更多评论   

感谢分享。
2012-02-20 11:19 | tms

只有注册用户登录后才能发表评论。


网站导航: