在Web页面中经常需要实现如图5-2所示的级联菜单的效果。即根据用户的选择,动态展开并显示出对应选项子菜单中的内容。本例中是根据用户所选择的商品类别信息,在子菜单中显示对应的商品名称。
图
5-2
级联菜单的效果
在传统的Web实现方式中,一般是在页面初始化时动态获取到服务器端数据库中对应所有子菜单中的信息,放置页面中对应的位置,然后在结合CSS层叠样式表动态控制对应子菜单的显示或者隐藏。
采用这种方法的弊端在于会造成浏览器端下载的页面非常臃肿,许多根本用不到的信息也必须提前装载到页面中。
而如果借助Ajax技术,我们可以实现当用户选择对应的菜单项后,将对应的请求以异步方式提交到服务器端,然后有选择地从服务器端获取到对应的子菜单信息,再返回浏览器端进行响应显示。
首先在Eclipse中新建一个Web项目,项目名称为P52_Menu,对应的浏览器端页面代码如下:
源文件:menu.jsp
<
%
@ page contentType="text/html;charset=UTF-8" language="java"
%
>
<head>
<META http-equiv=Content-Type content="text/html; charset=UTF-8">
<LINK href="images/css.css" type=text/css rel=stylesheet>
</head>
<script language="javascript">
var XMLHttpReq;
var currentSort;
//
创建
XMLHttpRequest
对象
function createXMLHttpRequest() {
if(window.XMLHttpRequest) { //Mozilla
浏览器
XMLHttpReq = new XMLHttpRequest();
}
else
if (window.ActiveXObject) { // IE
浏览器
try {
XMLHttpReq = new ActiveXObject("Msxml2.XMLHTTP");
} catch
(e)
{
try
{
XMLHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {}
}
}
}
//
发送请求函数
function sendRequest(url) {
createXMLHttpRequest();
XMLHttpReq.open("GET", url, true);
XMLHttpReq.onreadystatechange = processResponse;//
指定响应函数
XMLHttpReq.send(null); //
发送请求
}
//
处理返回信息函数
function processResponse() {
if
(XMLHttpReq.readyState == 4) { //
判断对象状态
if (XMLHttpReq.status == 200) { //
信息已经成功返回,开始处理信息
updateMenu();
}
else
{ //
页面不正常
alert("
您所请求的页面有异常。
");
}
}
}
//
更新菜单函数
function updateMenu() {
var res=XMLHttpReq.responseXML.getElementsByTagName("res")
var subMenu = "";
for(var i = 0; i < res.length; i++) {
subMenu = subMenu + " " + res[i].firstChild.data + "<br>";
}
currentSort.innerHTML = subMenu;
}
//
创建级联菜单函数
function showSubMenu(obj) {
currentSort =document.getElementById(obj);
currentSort.parentNode.style.display = "";
sendRequest("menu?sort=" + obj);
}
</script>
<table style="BORDER-COLLAPSE: collapse" borderColor=#111111
cellSpacing=0 cellPadding=0 width=200 bgColor=#f5efe7 border=0>
<TR>
<TD align=middle height=4><IMG height=4
src="images/promo_list_top.gif" width="100
%
"
border=0>
</TD>
</TR>
<TR>
<TD align=middle bgColor=#dbc2b0
height=19><B>
笔记本品牌
</B>
</TD>
</TR>
<tr>
<td height="20">
<a onClick="showSubMenu('IBM')">IBM</a>
</td>
</tr>
<tr style="display:none">
<td height="20" id="IBM"> </td>
</tr>
<tr>
<td height="20">
<a onClick="showSubMenu('SONY')">SONY</a>
</td>
</tr>
<tr style="display:none ">
<td id="SONY" height="20"> </td>
</tr>
</table>
在该页面中提供了对应的菜单以供用户进行选择,用户选择菜单后,将调用“
showSubMenu('XXX')
”
函数,该函数带参数,其中参数用于传递所选菜单项的标志信息,以决定获取服务器端的哪个子菜单信息。在“
showSubMenu('XXX')
”
函数中首先获取到所选菜单项的识别信息,然后再借助
Ajax
提交请求,并同时提交用户所选菜单的标识信息到服务器端,等待服务器端的处理。当服务器端处理完成后,将返回对应的子菜单信息,在
Ajax
提供的处理函数中对应菜单项的位置进行显示,这里用
innerHTML
属性实现定位显示。
该Web应用的配置文件web.xml对应的代码如下所示。从该配置文件中可以了解到,当浏览器端提交“
menu”请求时,将由服务器端的类名为“
classmate.MenuAction
”的Servlet程序进行处理。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<servlet>
<servlet-name>ms1</servlet-name>
<servlet-class>classmate.MenuAction</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ms1</servlet-name>
<url-pattern>/menu</url-pattern>
</servlet-mapping>
<!-- The Welcome File List -->
<welcome-file-list>
<welcome-file>menu.jsp</welcome-file>
</welcome-file-list>
</web-app>
下面我们关注一下服务器端Servlet程序MenuAction.java中对应的程序代码。当接收到浏览器端提交的请求后,Servlet程序将首先获取浏览器端提交的所选菜单项的标志信息,即所选择的商品类别信息,然后借助封装了数据库操作的JavaBean完成数据库的查询工作,依据类别获取到对应商品名称的信息。
package classmate;
import java.io.IOException;
……
public class MenuAction extends HttpServlet {
public void init(ServletConfig config) throws ServletException {
}
/
*
*
处理
<GET>
请求方法
*
/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//
设置接收信息的字符集
request.setCharacterEncoding("UTF-8");
//
接收浏览器端提交的信息
String sort = request.getParameter("sort");
//
设置输出信息的格式及字符集
response.setContentType("text/xml; charset=UTF-8");
response.setHeader("Cache-Control", "no-cache");
//
创建输出流对象
PrintWriter out = response.getWriter();
//
依据验证结果输出不同的数据信息
out.println("<response>");
//
数据库操作
DB db = new DB();
ResultSet rs;
String strSql=null;
//
查找该品牌具体型号
strSql = "select product.name from sort,product where sort.id=product.sortid
and sort.name='"+ sort + "'";
rs = db.executeQuery(strSql);
try {
while (rs.next()) {
out.println("<res>" + rs.getString("name") + "</res>");
}
}
catch (SQLException e) {
e.printStackTrace();
}
out.println("</response>");
out.close();
}
}
注意在本例中,返回的XML文档的格式如下所示:
<response>
<res>
商品名称
1</ res>
<res>
商品名称
2</ res>
</response>
提示:
读者可以进一步完善该程序,实现从服务器端动态获取菜单项信息,然后再依据用户选择动态显示子菜单信息的效果。
这里所说的刷新,指的是通过重发
URL
请求来从服务器获得更新的数据以更新视图的显示。
实现动态加载列表框 本例中所实现的效果如图5-3所示。当用户在品牌选择的下拉列表框中选择了对应品牌后,该品牌下所有的商品信息将会动态出现在商品选择列表框中以供用户进一步选择。这种表单元素之间的联动效果在网页中非常常用。例如,随着所选专业,显示班级选择列表。随着所选部门,显示职务选择列表等。
传统的Web实现方式,页面初始化时准备好所有列表框中的信息,并通过逻辑控制建立列表框之间对应选项的联系。再依据用户的选择,通过逻辑判断将事先准备好的列表框信息装入对应的联动列表框中。
这种方法的弊端是造成浏览器端下载的页面非常臃肿,许多在本次交互中根本用不到的信息也必须提前装载到页面中。

图5-3 动态加载列表框的效果
借助Ajax技术,可以实现当用户选择第一个列表框中对应的选项后,将对应的请求以异步方式提交到服务器端,然后有选择地从服务器端获取到下一个列表框中的列表信息,再返回浏览器端进行响应显示,下面介绍一下具体的实现过程。
首先在Eclipse中新建一个Web项目,项目名称为P53_DyList,对应的浏览器端页面代码如下:
源文件:dyList.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<head>
<META http-equiv=Content-Type content="text/html; charset=UTF-8">
</head>
<script language="javascript">
var XMLHttpReq;
//创建XMLHttpRequest对象
function createXMLHttpRequest() {
if(window.XMLHttpRequest) { //Mozilla 浏览器
XMLHttpReq = new XMLHttpRequest();
}
else if (window.ActiveXObject) { // IE浏览器
try {
XMLHttpReq = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
XMLHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {}
}
}
}
//发送请求函数
function sendRequest(url) {
createXMLHttpRequest();
XMLHttpReq.open("GET", url, true);
XMLHttpReq.onreadystatechange = processResponse;//指定响应函数
XMLHttpReq.send(null); // 发送请求
}
// 处理返回信息函数
function processResponse() {
if (XMLHttpReq.readyState == 4) { // 判断对象状态
if (XMLHttpReq.status == 200) { // 信息已经成功返回,开始处理信息
updateList();
} else { //页面不正常
window.alert("您所请求的页面有异常。");
}
}
}
// 刷新列表框函数
function refreshList() {
var sort = document.getElementById("sort").value;
if(sort == "" ) {
clearList();
return;
}
var url = "dyList?sort=" + sort;
sendRequest(url)
}
// 更新列表框中列表项函数
function updateList() {
clearList();
var product = document.getElementById("product");
var results = XMLHttpReq.responseXML.getElementsByTagName("name");
var option = null;
for(var i = 0; i < results.length; i++) {
option = document.createElement("option");
option.appendChild(document.createTextNode(results[i].firstChild. nodeValue));
product.appendChild(option);
}
}
// 清除列表框中原有选项的函数
function clearList() {
var product = document.getElementById("product");
while(product.childNodes.length > 0) {
product.removeChild(product.childNodes[0]);
}
}
</script>
<table style="BORDER-COLLAPSE: collapse" borderColor=#111111
cellSpacing=0 cellPadding=2 width=200 bgColor=#f5efe7 border=0>
<TR>
<TD align=middle height=4 colspan="2"><IMG height=4
src="images/promo_list_top.gif" width="100%"
border=0>
</TD>
</TR>
<TR>
<TD align=middle bgColor=#dbc2b0
height=19 colspan="2"><B>商品搜索</B>
</TD>
</TR>
<tr>
<td height="20">
品牌选择:
</td>
<td height="20">
<select id="sort" οnchange="refreshList();">
<option value="default">请选择</option>
<option value="IBM">IBM</option>
<option value="SONY">SONY</option>
<option value="联想">联想</option>
</select>
</td>
</tr>
<tr>