在实际Web页面中,有一些数据是需要实时反馈给浏览者的,但是完全刷新当前页面从而改变页面部分内容将会是很不友好的用户体验,并且浏览者也不容易发现哪些数据或内容是重新加载的。此时,使用Ajax技术定时向服务器发送改变页面内容请求,从而即可实现页面内容自动刷新的效果。
以下实例通过一个按钮点击事件来出发页面自动刷新效果,通常在实际开发中会使用onload事件取代。js代码中较多地使用了setTimeout()方法来定时执行特定的函数,通过响应信息的内容对DOM对象进行动态修改。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script>
var xhr;
function createXhr(){
if (window.XMLHttpRequest){// code for IE7+, Firefox, Chrome, Opera, Safari
xhr=new XMLHttpRequest();
} else {// code for IE6, IE5
xhr=new ActiveXObject("Microsoft.XMLHTTP");
}
}
function getStart(){
createXhr();
var url = "AutoRefresh?task=reset";
xhr.open("GET",url,true);
xhr.onreadystatechange = doCallback;
xhr.send(null);
}
function doCallback(){
if(xhr.readyState == 4){
if(xhr.status == 200){
setTimeout("respServer()", 5000);
refreshTime();
}
}
}
function respServer(){
createXhr();
var url = "AutoRefresh?task=ref";
xhr.open("GET",url,true);
xhr.onreadystatechange = refCallback;
xhr.send(null);
}
function refCallback(){
if(xhr.readyState == 4){
if(xhr.status == 200){
var message = xhr.responseXML.getElementsByTagName("message")[0].firstChild.data;
if(message != "done"){
var new_row = createRow(message);
var table = document.getElementById("tab");
var t_body = table.getElementsByTagName("tbody").item(0);
var first_row = t_body.getElementsByTagName("tr").item(1);
t_body.insertBefore(new_row, first_row);
setTimeout("respServer()", 5000);
refreshTime();
}
}
}
}
function refreshTime(){
var time_span = document.getElementById("time");
var time_val = time_span.innerHTML;
var int_val = parseInt(time_val);
var new_val = int_val - 1;
if(new_val > 0 ){
setTimeout("refreshTime()", 1000);
time_span.innerHTML = new_val;
} else {
time_span.innerHTML = 5;
}
}
function createRow(message){
var row = document.createElement("tr");
var cell = document.createElement("td");
var data = document.createTextNode(message);
cell.appendChild(data);
row.appendChild(cell);
return row;
}
</script>
</head>
<body>
<h2>Auto fresh page</h2>
<input type="button" value="start" οnclick="getStart();">
<p>
Page will refresh in <span id="time">5</span> seconds.
</p>
<table id="tab" align="left">
<tbody>
<tr><td></td></tr>
</tbody>
</table>
</body>
</html>
服务端代码较为简洁,仅仅是通过计数器的变化返回一些不同的信息。最终响应信息将使用XML格式进行传输,客户端需要将XML处理为DOM对象进行解析。
package com.any.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class AutoRefresh
*/
@WebServlet("/AutoRefresh")
public class AutoRefresh extends HttpServlet {
private static final long serialVersionUID = 1L;
private int counter = 1;
/**
* @see HttpServlet#HttpServlet()
*/
public AutoRefresh() {
super();
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String res = "";
String task = request.getParameter("task");
String message = "";
if(task.equals("reset")){
counter = 1;
} else {
switch(counter){
case 1:message="message 1";break;
case 2:message="message 2";break;
case 3:message="message 3";break;
case 4:message="message 4";break;
case 5:message="message 5";break;
case 6:message="message 6";break;
case 7:message="done";break;
}
counter++;
}
res = "<message>"+message+"</message>";
response.setContentType("text/xml");
response.setHeader("Cache-Control", "no-cache");
PrintWriter out = response.getWriter();
out.println("<response>");
out.println(res);
out.println("</response>");
out.close();
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
}
}
启动并进入当前页面后,点击start按钮即可发现页面在自动读取响应信息,并将信息展示在当前页面,整个页面也没有进行重新绘制。
另外,在实际应用中,我们会经常遇到开发一个进度条的情况。通常的做法是选择插件,本文将不依赖于任何插件,通过Ajax技术每隔1.5秒向服务器发送一次数据请求,返回当前任务进度,从而展示在页面上。客户端仅需要根据服务端返回任务进度数据的第一位来控制进度条中进度块的着色即可。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script>
var xhr;
var key;
var bar_color = 'gray';
var span_id="block";
var clear = " ";
function createXhr(){
if (window.XMLHttpRequest){// code for IE7+, Firefox, Chrome, Opera, Safari
xhr=new XMLHttpRequest();
} else {// code for IE6, IE5
xhr=new ActiveXObject("Microsoft.XMLHTTP");
}
}
function go() {
createXhr();
checkDiv();
var url = "ProgressExam?task=create";
var button = document.getElementById("go");
button.disabled=true;
xhr.open("GET", url, true);
xhr.onreadystatechange = goCallback;
xhr.send(null);
}
function goCallback(){
if(xhr.readyState == 4){
if(xhr.status == 200){
setTimeout("respServer()", 1500);
}
}
}
function respServer(){
createXhr();
var url = "ProgressExam?task=ref&key="+key;
xhr.open("GET", url, true);
xhr.onreadystatechange = refCallback;
xhr.send(null);
}
function refCallback(){
if(xhr.readyState == 4){
if(xhr.status == 200){
var percent = xhr.responseXML.getElementsByTagName("percent")[0].firstChild.data;
var index = processResult(percent);
for(var i =1;i<=index;i++){
var elem = document.getElementById("block"+i);
elem.innerHTML = clear;
elem.style.backgroundColor = bar_color;
var next_cell = i+1;
if(next_cell>index&&next_cell<=9){
document.getElementById("block"+next_cell).innerHTML = percent + "%";
}
}
if(index<9){
setTimeout("respServer()",1500);
} else {
document.getElementById("complete").innerHTML = "complete!";
document.getElementById("go").disabled = false;
}
}
}
}
function processResult(percent){
var idx;
if(percent.length == 1){
idx = 1;
} else if(percent.length == 2){
idx = percent.substring(0,1);
} else {
idx = 9;
}
return idx;
}
function checkDiv(){
var progress_bar = document.getElementById("bar");
if(progress_bar.style.visibility == "visible"){
clearBar();
document.getElementById("complete").innerHTML = " ";
}else{
progress_bar.style.visibility = "visible";
}
}
function clearBar(){
for(var i = 1;i<10;i++){
var elem = document.getElementById("block"+i);
elem.innerHTML = clear;
elem.style.backgroundColor = "white";
}
}
</script>
</head>
<body>
<h2>Launch progress bar</h2>
<input type="button" value="start" id="go" οnclick="go();">
<p>
<table align="center">
<tr><td>
<div id="bar" style="padding:2px;border:solid black 2px;visibility: hidden">
<span id="block1"> </span>
<span id="block2"> </span>
<span id="block3"> </span>
<span id="block4"> </span>
<span id="block5"> </span>
<span id="block6"> </span>
<span id="block7"> </span>
<span id="block8"> </span>
<span id="block9"> </span>
</div>
</td></tr>
<tr><td id="complete" align="center"></td></tr>
</table>
</p>
</body>
</html>
服务端的代码是一个虚拟任务,反应的是任务执行进度,仅仅需要向客户端反馈当前任务执行的进度百分比即可。
package com.any.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class ProgressExam
*/
@WebServlet("/ProgressExam")
public class ProgressExam extends HttpServlet {
private static final long serialVersionUID = 1L;
private int counter = 1;
/**
* @see HttpServlet#HttpServlet()
*/
public ProgressExam() {
super();
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String task = request.getParameter("task");
String res = "";
if(task.equals("create")){
res = "<key>1</key>";
counter = 1;
}else{
String percent = "";
switch(counter){
case 1:percent = "10";break;
case 2:percent = "21";break;
case 3:percent = "35";break;
case 4:percent = "52";break;
case 5:percent = "67";break;
case 6:percent = "75";break;
case 7:percent = "88";break;
case 8:percent = "100";break;
}
counter++;
res = "<percent>"+percent+"</percent>";
}
PrintWriter out = response.getWriter();
response.setContentType("text/xml");
response.setHeader("Cache-Control", "no-cache");
out.println("<response>");
out.println(res);
out.println("</response>");
out.close();
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}