浏览器的开发都是基于传统的内容显示页面模型。默认情况下,点击链接或者提交表单时,浏览器会向服务器请求一个新的页面。这种情况下,浏览器会马上给用户一个反馈,告诉他们浏览器正在处理某些信息。
大多数浏览器都用动画的形式显示这种反馈。Apple的Safari会在地址栏的背景中呈现一个正在扩展的颜色带。而微软的IE,在用户请求新页面时,会让原本右上角静止的图标旋转起来,如图6-5所示。

图6-5 在请求新页面时,微软IE的图标开始旋转
通过Ajax,获取新页面的这种默认的浏览器行为可被用JavaScript和事件处理函数编写的自定义动作所取代。因为把常规的行为取消了,浏览器也就不再对正发生的事做任何提示。要靠我们来给用户提供某种反馈。
理想情况下,会马上收到Ajax的响应。然而现实中,通过Ajax请求的资源会被诸如网络拥堵等瓶颈所制约。响应的速度取决于带宽、延迟等其他影响网络数据传输的因素。
对于浏览基于Ajax的页面的用户来说,可能会看不到这个反馈。如果点击链接或提交表单没有马上收到回应,可推测出一定是什么地方出了毛病。
为了解决这个问题,Ajax脚本应当具备相应的机制,用于提示某个操作正在执行中。你可以使用DOM脚本编程向页面中插入一段解释性的文字。比如,在某个合适的元素中插入“Loading...”等类似的字样。
使用动画则是一个更有效的办法。效仿IE浏览器,创建一张旋转的动态图片,在成功收到响应前,会一直显示这张图片。
动态的GIF图片是最简单的格式。具体的图片可由你的喜好而定,只要它能显示出一种循环的动画效果就可以。旋转的图形、转圈的箭头与螺旋的进度条都是常见的“活动”图片,如图6-6所示。

function displayLoading(element) {
while (element.hasChildNodes()) {
element.removeChild(element.lastChild);
}
var image = document.createElement("img");
image.setAttribute("src","loading.gif");
image.setAttribute("alt","Loading...");
element.appendChild(image);
}
现在,用这个函数对联系方式例子做一点修改。我们想在函数grabFile中发出Ajax请求的同时,也执行这个函数:
function grabFile(file) {
var request = getHTTPObject();
if (request) {
displayLoading(document.getElementById ("deta ils "));
request.onreadystatechange = function() {
parseResponse(request);
};
request.open("GET", file, true);
request.send(null);
return true;
} else {
return false;
}
}
当点击某个名字后,在id为details的div中(人物的联系方式也将显示在这里)就会显示出GIF动画,如图6-7所示。

图6-7 旋转的图片会告诉用户浏览器正在对信息进行处理
一旦Ajax请求完毕,那个图片会被函数parseResponse的innerHTML属性所代替:
function parseResponse(request) {
if (request.readyState == 4) {
if (request.status == 200 || request.status == 304) {
var details = document.getElementById("details");
details.innerHTML = request.responseText;
}
}
}
对于联系方式表单来说,我们想把GIF动画显示在被提交表单的下方。对函数displayLoading做一点修改,使其在添加图片之前,不用再清空包含图片的元素中的节点。这次想用一个进度条:
function displayLoading(element) {
var image = document.createElement("img");
image.setAttribute("src","progressbar.gif");
image.setAttribute("alt","Loading...");
element.appendChild(image);
}
只需修改函数sendData:
function sendData(data) {
var request = getHTTPObject();
if (request) {
displayLoading(document.getElementById("contactfor m"));
request.onreadystatechange = function() {
parseResponse(request);
};
request.open( "POST", "formlogic.php", true );
request.setRequestHeader("Content-Type",
"application/x-www-form-urlencoded");
request.send(data);
return true;
} else {
return false;
}
}
提交表单的同时,进度条也会显示出来,如图6-8所示。

图6-8 联系方式表单下的进度条表明浏览器正在对信息进行处理
刚刚发生了什么
能够表示出“处理中”的状态很重要,同样,如果能显示出刚刚发生了什么也是个很不错的想法。
在37signals(www.37signals.com)创建的一系列Ajax应用中,率先采用了黄色淡出(yellow fade)技术。把JavaScript与CSS相结合,使网页中刚更新过的元素的背景色由黄渐变为白。这种方式可有效地显示出当前页面哪些部分刚刚被更新过,如图6-9所示。

图6-9 黄色淡出技术的显示效果
很多网站都采用了黄色淡出技术,可以说,它已成为一种约定俗成的做法。这样很好。用户已经接受了这种做法。伴随着视觉反馈技术的广泛应用,它的含义也不言自明。
下面这个函数会让元素的背景色渐变成白色:
function fadeUp(element,red,green,blue) {
if (element.fade) {
clearTimeout(element.fade);
}
element.style.backgroundColor = "rgb("+red+"," +green +",
"+blue+")";
if (red == 255 && green == 255 && blue == 255) {
return;
}
var newred = red + Math.ceil((255 - red)/10);
var newgreen = green + Math.ceil((255 - green)/10);
var newblue = blue + Math.ceil((255 - blue)/10);
var repeat = function() {
fadeUp(element,newred,newgreen,newblue)
};
element.fade = setTimeout(repeat,100);
}
函数fadeUp需要4个参数。第一个是要改变背景色的元素名。另外3个参数是RGB值:红、绿和蓝。这些是元素背景色的起始RGB值:
function fadeUp(element,red,green,blue)
元素style属性的backgroundColor通过红、绿、蓝这3个值来改变。借助CSS,你可用十六进制或RGB值声明颜色:
element.style.backgroundColor = "rgb("+red+","+ green +",
"+blue+")";
这是一个递归函数,也就是说它自己调用自己。每次调用前都会有一个小暂停,用setTimeout函数来实现,它带有两个参数:要执行的函数和执行前需等待的时间(以毫秒计):
var repeat = function() {
fadeUp(element,newred,newgreen,newblue)
};
element.fade = setTimeout(repeat,100);
在这个例子里,把超时函数赋给一个自定义的属性——fade。每次调用该函数时,都用clearTimeout把时间归零。这就确保了在一个元素上多次调用函数fadeUp时,也不会发生任何的指令冲突:
if (element.fade) {
clearTimeout(element.fade);
}
在下次调用函数前,RGB的值会逐渐趋向255:
var newred = red + Math.ceil((255 - red)/10);
var newgreen = green + Math.ceil((255 - green)/10);
var newblue = blue + Math.ceil((255 - blue)/10);
当每个值都变成255后,元素的背景色就变成白色了:rgb(255,255, 255)。此时,无需再调用函数:
if (red == 255 && green == 255 && blue == 255) {
return;
}
只要文档背景色为白,就可用fadeUp函数实现黄色淡出效果,或其他任何颜色的淡出。
修改函数parseResponse,为联系方式页面添加黄色淡出效果:
function parseResponse(request) {
if (request.readyState == 4) {
if (request.status == 200 || request.status == 304) {
var details = document.getElementById("details");
details.innerHTML = request.responseText;
fadeUp(details,255,255,153);
}
}
}
这里首先定义了一个黄色阴影:rgb(255,255,153)。当收到Ajax响应后,这个颜色会渐变成白色,如图6-10所示。

图6-10 用渐变色提示页面更新的部分
我们通常使用黄色,因为用户已从其他的Ajax程序中习惯了这个颜色。除了这种情况,渐变色还可用于添加上下文(add context)。在联系方式表单里,你可以用红色阴影标注错误提示,如图6-11所示。

图6-11 用浅红色标注问题区域
我们写的这个fadeUp函数是最基础的,它只适用于文档为白色背景的情况。更多复杂的脚本,请参见Fade Anything Technique(www.axentric. com/aside/fat/)。