动态加载的 FAQ
根据邮政编码获取地区信息
动态树形列表
多级联动菜单
条件设置向导
页面关键词提示
在使用 Ajax 技术编写的网页应用程序中,动态加载数据,无刷新更新客户端页面
是最为常见的一种形式。这种方式给用户带来了良好的使用体验,大多数情况下能够加
快页面下载速度,减轻服务器压力。本章挑选了 6 个实例讲解如何利用 Ajax 技术动态
加载数据。
在本章中可以了解到 XMLHttpRequest 对象的基本使用方法,服务器返回信息的一
些常见格式,包括文本、XML、JSON 等。还可以学习到不同浏览器的事件对象获取方
法,以及使用 JavaScript 将信息在客户端进行缓存的方法。
动态加载数据
第
章
Ajax 经典案例开发大全
·2·
1.1 动态加载的 FAQ
FAQ 的英文全称是 Frequently Asked Questions,即常见问题。在
很多网站中都包含该功能。当页面上列出的问题很多时,加载过程往
往比较慢。而浏览者也许只想查看其中的几个问题。利用 Ajax 技术
可以动态加载用户感兴趣的问题,很好地解决这个矛盾。实例运行效
果如图 1.1 所示。
1.1.1 技术要点
动态加载 FAQ 的过程主要是利用 XMLHttpRequest(以下简称 XHR)对象与服务端通信,根据用
户单击的感兴趣问题动态将内容加载到页面中。在具体实现时,有两点要注意的内容。
1.对每个问题进行唯一标识
FAQ 主要包含问题与解答两个部分,用户单击一个问题时,服务器必须知道请求的是哪个问题的
解答,所以必须对每个问题进行唯一标识。标识的方法很多,在本例中简单使用数字进行标识。每个
问题在页面上表现为超链接,单击链接将触发 onclick 事件,调用 loadFAQ 函数,传入问题标识,获取
对应的解答。
单击后并不是要真正链接到一个新的页面,所以在<a>标签的 onclick 事件中 return false 取消原有
链接的功能。每个答案分配一个 div 用于显示,每个 div 的 id 属性命名规则为,在对应的问题数字标
识前统一增加“faqDetail”。
2.对已加载的解答不重复向服务器发出请求
问题的解答加载后,将显示在对应问题下方的 div 中。当用户再次单击问题时该 div 将隐藏起来。
如果用户第三次单击相同的问题,由于解答已加载到页面,所以不需要再次向服务器发送请求,只需
将隐藏的 div 显示出来即可。
隐藏和显示主要通过设置 div 样式中的 display 属性来完成,当 display 属性设置为“none”时隐藏,
设置为“block”时显示。判断是否需要发出请求,可以检查 div 的 innerHTML 是否包含内容。
1.1.2 数据库设计
本实例使用名为 faq 的数据库表,包含的数据如图 1.2 所示。具体的创建数据表语句如下:
CREATE TABLE 'faq' (
'id' int(11) NOT NULL auto_increment,
'faq' varchar(255) NOT NULL,
'detail' varchar(255) NOT NULL,
PRIMARY KEY ('id')
)
图 1.1 实例运行效果
第 1 章 动态加载数据
·3·
图 1.2 表 faq 包含的数据
主要包括两个文件:用户操作界面 index.jsp 和服务器端响应文件 read_faq.jsp。
1.1.3 用户操作界面 index.jsp
页面中显示了 3 个问题,分别编号为 1、2、3。每个问题表现为一个超链接,单击超链接触发 loadFAQ
函数。每个问题下面包含一个用于显示答案的 div,id 属性设置为“faqDetail+问题编号”,通过
style="display:none"默认设置为隐藏。详细的函数说明请参考代码中的注释。
<%@ page contentType="text/plain; charset=UTF-8"%>
<%@ page language="java"%>
<%@ page import="java.sql.*,ajax.db.DBUtils"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<head>
<title>动态加载的 FAQ</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<script type="text/javascript">
var xmlHttp; //用于保存 XMLHttpRequest 对象的全局变量
var currFaqId; //用于保存当前想要获取的 FAQ 编号
//用于创建 XMLHttpRequest 对象
function createXmlHttp() {
//根据 window.XMLHttpRequest 对象是否存在使用不同的创建方式
if (window.XMLHttpRequest) {
xmlHttp = new XMLHttpRequest(); //FireFox、Opera 等浏览器支持的创建方式
} else {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); //IE 浏览器支持的创建方式
}
}
//获取 FAQ 信息的调用函数
function loadFAQ(faqId) {
currFaqId = faqId; //记录当前想要获取的 FAQ 编号
var currFaqDetail = getFaqDetailDiv(faqId); //获取对应的 faqDetail 节点
if (currFaqDetail.style.display=="none") {
currFaqDetail.style.display = "block" //设置 div 状态为“显示”
//判断 FAQ 详细信息是否已存在,如果不存在则从服务器获取
if (currFaqDetail.innerHTML == "") {
createXmlHttp(); //创建 XmlHttpRequest 对象
xmlHttp.onreadystatechange = loadFAQCallback;
Ajax 经典案例开发大全
·4·
xmlHttp.open("GET", "read_faq.jsp?faqId=" + faqId, true);
xmlHttp.send(null);
}
} else {
currFaqDetail.style.display = "none"; //设置 div 状态为“隐藏”
}
}
//获取 FAQ 信息的回调函数
function loadFAQCallback() {
if (xmlHttp.readyState == 4) {
//将 FAQ 信息写入到对应的 div 中
getFaqDetailDiv(currFaqId).innerHTML = xmlHttp.responseText;
}
}
//根据 faqId 取得对应的 div 节点
function getFaqDetailDiv(faqId) {
return document.getElementById("faqDetail" + faqId);
}
</script>
</head>
<body>
<h1>FAQ(常见问题)</h1>
<%
String sql = "select id, faq from faq order by id asc";//定义查询数据库的 SQL 语句
Connection conn = null; //声明 Connection 对象
PreparedStatement pstmt = null; //声明 PreparedStatement 对象
ResultSet rs = null; //声明 ResultSet 对象
try {
conn = DBUtils.getConnection(); //获取数据库连接
pstmt = conn.prepareStatement(sql); //根据 sql 创建 PreparedStatement
rs = pstmt.executeQuery(); //执行查询,返回结果集
while (rs.next()) { //遍历结果集
%>
<div>
<a href="#" onclick="loadFAQ(<%=rs.getInt(1)%>);return false;">
<%=rs.getString(2)%>
</a>
</div>
<div id="faqDetail<%=rs.getInt(1)%>" style="display:none"></div>
<%
}
} catch (SQLException e) {
System.out.println(e.toString());
} finally {
DBUtils.close(rs); //关闭结果集
第 1 章 动态加载数据
·5·
DBUtils.close(pstmt); //关闭 PreparedStatement
DBUtils.close(conn); //关闭连接
}
%>
</body>
</html>
1.1.4 服务器端响应文件 read_faq.jsp
服务器响应文件根据用户传入的 faqId 参数,从数据库中查找对应的 FAQ 详细信息。详细信息可
以为包含 HTML 标记的内容。查询完毕后将结果返回。
<%@ page contentType="text/plain; charset=UTF-8"%>
<%@ page language="java"%>
<%@ page import="java.sql.*,ajax.db.DBUtils"%>
<%
out.clear(); //清空当前的输出内容(空格和换行符)
String faqIdStr = request.getParameter("faqId"); //获取 faqId 参数
String faqDetail = null; //用于保存 FAQ 详细信息
if (faqIdStr != null) {
int faqId = Integer.parseInt(faqIdStr); //将获取的 faqId 参数转换为数字
String sql = "select detail from faq where id = ?"; //定义查询数据库的 SQL 语句
Connection conn = null; //声明 Connection 对象
PreparedStatement pstmt = null; //声明 PreparedStatement 对象
ResultSet rs = null; //声明 ResultSet 对象
try {
conn = DBUtils.getConnection(); //获取数据库连接
pstmt = conn.prepareStatement(sql); //创建 PreparedStatement
pstmt.setInt(1, faqId); //设置参数
rs = pstmt.executeQuery(); //执行查询,返回结果集
if (rs.next()) {
faqDetail = rs.getString(1);
}
} catch (SQLException e) {
System.out.println(e.toString());
} finally {
DBUtils.close(rs); //关闭结果集
DBUtils.close(pstmt); //关闭 PreparedStatement
DBUtils.close(conn); //关闭连接
}
}
//根据 faqDetail 是否包含正确内容决定输出的信息
if (faqDetail != null) {
out.println(faqDetail);
} else {