Ajax實現動態的二級級聯菜單


 今天花了點時間用Ajax實現了一個二級級聯菜單。整理總結一下。為了把重點放在Ajax和級聯菜單的實現上,本文省略了數據庫建表語句和操作數據庫的代碼!

數據庫建表語句就不帖出來了。主要有兩張表,區域表:district。街道表:street。區域表和街道表是一對多關系,一個區域可以有零到多個街道,一條街道屬於一個區域。數據如下:

        

 

 頁面代碼 index.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="js/js.js"></script>
<title>Insert title here</title>
</head>
<body>
    <select id="district" onchange="cascade(this.value)" >
        <option value="-1">請選擇</option>
        <c:forEach items="${districts }" var="district">
            <option value="${district.id }">${district.name }</option>
        </c:forEach>
    </select>
    <select id="street" onchange="alert(this.value)">
        <option>請選擇</option>
    </select>
</body>
</html>

 

初始化主頁面一級菜單列表的Servlet代碼  InitServlet.java:

 1 package cascade.servlet;
 2 import java.io.IOException;
 3 import java.util.List;
 4 
 5 import javax.servlet.ServletException;
 6 import javax.servlet.http.HttpServlet;
 7 import javax.servlet.http.HttpServletRequest;
 8 import javax.servlet.http.HttpServletResponse;
 9 
10 import cascade.entity.District;
11 import cascade.service.DistrictService;
12 
13 
14 public class InitServlet extends HttpServlet{
15 
16     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
17         doPost(req, resp);
18     }
19 
20     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
21         req.setCharacterEncoding("UTF-8");
22         resp.setCharacterEncoding("UTF-8");
23         /*
24          * DistrictService  ds為操作數據庫的對象.
25          * 調用該對象的getAllDistrict()方法,可以從數據庫中取得所有的區域信息,封裝為List<District>對象,並返回。
26          * 其中District是數據庫District表的實體類 
27          * 為了把重點放在Ajax和級聯菜單的實現上,本文省略了操作數據庫的代碼!!!
28          */
29         DistrictService ds = new DistrictService();
30         List<District> districts = ds.getAllDistrict();
31         //List<District>對象存在request范圍中,並轉向到主頁
32         req.setAttribute("districts", districts);
33         req.getRequestDispatcher("index.jsp").forward(req, resp);
34     }
35     
36 }

 

web配置文件  web.xml:

在web.xml中添加如配置代碼

  <servlet>
      <servlet-name>init</servlet-name>
      <servlet-class>cascade.servlet.InitServlet</servlet-class>
  </servlet>
  <servlet-mapping>
      <servlet-name>init</servlet-name>
      <url-pattern>/index</url-pattern>
  </servlet-mapping>

此時,在瀏覽器中訪問 InitServlet.java (假設項目名為AjaxCascade,訪問地址就是:http://localhost:8080/AjaxCascade/index

數據庫的區域數據就已經填到第一級菜單項中了。 

此時頁面的源代碼可以看到下拉菜單(select)里每一項(option)的value也是從數據庫里取到的:

    <select id="district" onchange="cascade(this.value)" >
        <option value="-1">請選擇</option>
            <option value="1001">天河區</option>        
            <option value="1002">越秀區</option>        
            <option value="1003">海珠區</option>        
            <option value="1005">番禺區</option>        
            <option value="1000">白雲區</option>        
            <option value="1004">花都區</option>        
    </select>

 

現在開始現實街道下拉菜單(也就是頁面上id為street的select)的動態獲取。

我們知道,但區域菜單的值改變時,街道菜單的值也要動態的發生改變(如區域選擇“天河區”,街道菜單就應該動態加上“中山大道“這一項,如區域選擇“海珠區”,街道菜單就應該動態加上“昌崗路”,並刪除“中山大道“)。

為了現實上面所說的功能,要為區域菜單添加 onchange 事件的處理:onchange="cascade(this.value)" 當區域菜單值發生改變時調用cascade方法,並把自己的value屬性傳遞進去。

cascade代碼如下  js.js:

 1 //XMLHttpRequest組件
 2 var xhs;
 3 //區域菜單的值發生改變時調用該方法,並把區域菜單當前的value傳遞進來
 4 function cascade(id){
 5     //當id不大於0時,說明當前選擇的是“請選擇”這一項,則不做操作
 6     if(id>0){
 7         //請求字符串,把區域的id作為頁面參數傳到后台
 8         var url="cascade?id="+id;
 9         //創建XMLHttpRequest組件
10         xhs=new XMLHttpRequest();
11         //設置回調函數,processReuqest方法的定義在下面
12         xhs.onreadystatechange=processReuqest;
13         //打開與服務器的地址連接
14         xhs.open("post", url, true);
15         //發送請求
16         xhs.send(null);
17     }
18 }
19 
20 //processReuqest方法作為回調方法
21 function processReuqest(){
22     if(xhs.readyState==4){
23         if(xhs.status==200){
24             //創建新的select節點
25             var newSelect=document.createElement("select");
26             newSelect.id="street";
27             //為新創建的select節點添加onchange事件,以便測試用
28             newSelect.onchange=function test(){
29                 alert(this.value);
30             };
31             //為新創建的select節點添加option節點
32             var op=document.createElement("option");
33             op.value=-1;
34             op.innerHTML="請選擇";
35             newSelect.appendChild(op);
36             //得到完成請求后返回的字串符
37             var str = xhs.responseText;
38             //根據返回的字符串為新創建的select節點添加option節點
39             var arr1=str.split(",");
40             for(var i=0;i<arr1.length;i++){
41                 var arr2=arr1[i].split("=");
42                 var child=document.createElement("option");
43                 child.innerHTML=arr2[1];
44                 child.value=arr2[0];
45                 newSelect.appendChild(child);
46             }
47             //用新select節點替換舊的select節點
48             var select = document.getElementById("street");
49             document.body.replaceChild(newSelect, select);
50         }
51     }
52 }

XMLHttpRequest 對象:XMLHttpRequest 對象提供了對 HTTP 協議的完全的訪問,包括做出 POST 和 HEAD 請求以及普通的 GET 請求的能力。XMLHttpRequest 可以同步或異步地返回 Web 服務器的響應,並且能夠以文本或者一個 DOM 文檔的形式返回內容。盡管名為 XMLHttpRequest,它並不限於和 XML 文檔一起使用:它可以接收任何形式的文本文檔。XMLHttpRequest 對象是名為 AJAX 的 Web 應用程序架構的一項關鍵功能。

創建XMLHttpRequest 對象:盡管大部份瀏覽器都支持 new XMLHttpRequest() 來得到 XMLHttpRequest 對象,但IE瀏覽器和其他Web瀏覽器返回的 XMLHttpRequest 對象實例是不相同的,為了支持更多瀏覽器,建議編碼時如下所示的代碼創建XMLHttpRequest 實例。

function createXmlHttpRequest(){
    if(window.ActiveXObject){
        return new ActiveXObject("Microsoft.XMLHTTP");
    }else if(window.XMLHttpRequest){
        return new XMLHttpRequest();
    }
}

open(method,url,async)方法:建立於服務器的連接,method參數指定請求的HTTP方法。URL 參數指定請求的地址。acync 參數指定是否使用異步請求,其值為 true 或 false。

send(content)方法:發送請求,content參數指定請求的參數。當send方法不配置參數,即xhr.send()時,在IE中能夠正常運行,但在Firefox中卻不能,所以,建議最好加上null 。

onreadystatechange屬性:指定XMLHttpRequest對象的回調函數。onreadystatechange屬性作用與文本框的onblur等屬性一樣,是事件處理屬性,即當 XMLHttpRequest 的狀態發生改變時,XMLHttpRequest 對象都會解發onreadystatechange所指定的函數。

readyState屬性:XMLHttpRequest的狀態信息。XMLHttpRequest對象有如下幾種狀態。

0:XMLHttpRequest對象沒有完成初始化,此時,已經創建一個XMLHttpRequest對象,但是還沒有初始化。

1:XMLHttpRequest對象開始發送請求,此時,代碼已經調用open()方法並且XMLHttpRequest已經准備好把一個請求發送到服務器。

2:XMLHttpRequest對象的請求發送完成。此時,已經通過send()方法把一個請求發到服務器端,但是還沒有收到一個響應。

3:XMLHttpRequest對象開始讀取響應。此時,已經接收到HTTP響應頭部信息,但是消息體部分還沒有完全接收結束。

4:XMLHttpRequest對象讀取響應結束。些時,響應已被完全接收。

status屬性:HTTP的狀態碼,僅當readyState的值為3或4時,status屬性才可用。status屬性如下。

200:服務器響應正常。

400:無法找到請求的資源。

403:沒有訪問權限。

404:訪問資源不存在。

500:服務器內部錯誤。

responseText屬性:獲得響應的文本。當readyState值為0、1、2時,reponseText包含一下空字符串。當readyState值為3時,響應中包含還未完成的響應信息。當readyState值為4時,readyState包含完整的響應信息。

 

接下來是后台代碼的實現,從cascade方法可以看到,XMLHttpRequest對象是請求到名為cascade的地址上的。

CascadeServlet.java:

 1 package cascade.servlet;
 2 import java.io.IOException;
 3 import java.io.PrintWriter;
 4 import java.util.List;
 5 
 6 import javax.servlet.ServletException;
 7 import javax.servlet.http.HttpServlet;
 8 import javax.servlet.http.HttpServletRequest;
 9 import javax.servlet.http.HttpServletResponse;
10 
11 import cascade.entity.District;
12 import cascade.entity.Street;
13 import cascade.service.StreetService;
14 
15 
16 public class CascadeServlet extends HttpServlet{
17 
18     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
19         doPost(req, resp);
20     }
21 
22     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
23         req.setCharacterEncoding("UTF-8");
24         resp.setCharacterEncoding("UTF-8");
25         int id =Integer.parseInt(req.getParameter("id"));
26         District district=new District();
27         district.setId(id);
28         
29         /*
30          * StreetService  ss為操作數據庫的對象.
31          * 調用該對象的getAllStreet()方法,可以從數據庫中取得所有的區域信息,封裝為List<Street>對象,並返回。
32          * 其中Street是數據庫Street表的實體類 
33          * 為了把重點放在Ajax和級聯菜單的實現上,本文省略了操作數據庫的代碼!!!
34          */
35         StreetService ss=new StreetService();
36         List<Street> streets=ss.getAllStreet(district);
37         //把得到的街道對象集合拼接成字符串文本
38         StringBuffer sb=new StringBuffer();
39         for(int i=0;i<streets.size();i++){
40             sb.append(streets.get(i).getId()).append("=").append(streets.get(i).getName());
41             if(i!=streets.size()-1){
42                 sb.append(",");
43             }
44         }
45         //servlet不轉向或重定向到任何頁面,使用resp.getWriter().print()方法可以把文本響應給XMLHttpRequest對象
46          PrintWriter out = resp.getWriter();
47          out.print(sb.toString());
48          out.flush();
49          out.close();
50     }
51     
52 }

 

在web.xml中的配置:

  <servlet>
      <servlet-name>cascade</servlet-name>
      <servlet-class>cascade.servlet.CascadeServlet</servlet-class>
  </servlet>
  <servlet-mapping>
      <servlet-name>cascade</servlet-name>
      <url-pattern>/cascade</url-pattern>
  </servlet-mapping>

 

完工,效果如下:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM