AjaxAnywhere的官方站点是http://ajaxanywhere.sourceforge.net,本书撰写的时候最新的版本是1.1.0.6,读者可以从sourceforge.net下载到最新的jar开发包、src源码包,以及一个demo演示包。本书使用AjaxAnywhere1.1.0.6版本。
AjaxAnywhere使用“分区刷新”的思路,其工作原理如下。
(1)使用AjaxAnywhere自定义标签库将一个Web页面划分为几个可重载的区域(reload-capable zones)。
(2)使用AjaxAnywhere Javascript 应用编程接口(API)替代传统通信机制下表单提交方式。
(3)当请求在服务器端处理的时候,决定那些页面区域可以刷新(refresh)。这个过程可以使用基于客户端的Javascript或者基于服务器端的AjaxAnywhere应用编程接口(API)。
(4)在服务器端,AjaxAnywhere会生成包含即将更新的HTML代码的XML文档。
(5)在客户端,AjaxAnywhere Javascript接受这个XML文档,解析文档,并更新指定的页面区域。
采取这样的设计思路,可以尽可能地降低Javascript代码量,降低Ajax的开发门槛。
— 无须掌握和开发那么多的Javascript代码。
由于缺乏被广泛接受的命名习惯、格式化规则和模式,使得Javascript编码相对Java/JSP复杂许多,尤其在浏览器兼容性方面缺乏有效的调试和单元测试手段。使用AjaxAnywhere可以摆脱这些Javascript的复杂性。
— 方便集成。
使用AjaxAnywhere无须改变底层的应用程序代码。
— 降低技术风险。
可以随时在传统的通信机制和Ajax之间切换,允许Web应用程序同时支持两种通信机制。
— 平滑的兼容性。
再也不用在使用Ajax还是传统的交互方式间摇摆了,使用Ajax AnyWhere的Web应用程序可以兼容两种请求方式。
AjaxAnywhere的客户端脚本经过了IE,Mozilla Firefox和Opera等浏览器的兼容性测试,能够最大程度地保证代码的浏览器兼容性。
另外,还需要注意的AjaxAnywhere特性是,Ajax接收到的Ajax代码采用特殊的方式处理。AjaxAnywhere通过eval("")的方式执行这些Javascript代码,也可以将所定义的Javascript函数保存在适当的上下文(Context)中。不过,在允许Ajax方式重载的页面区域,不允许执行document.write()之类的Javascript语句。
允许重载的区域可能在提交请求之前就确定了,这种情况下需要重载客户端的AjaxAnywhere.getZonesToReload()的Javascript函数,不需要额外的服务器逻辑处理。
如果希望AjaxAnywhere重载整个文档,则重载后的AjaxAnywhere.getZonesToReload()函数必须返回“document.all”字符串,也可以在服务器端调用AAUtils.setRefreshAll(true)刷新整个页面。
相应的,Ajax请求中的response.sendRedirect()会被转化成Javascript代码的location.replace()命令。
Ajax Anywhere安装
如果要将AjaxAnywhere集成到自己的Web应用程序中,可以通过以下5个步骤来完成简单的配置。
第一步:下载最新的AjaxAnywhere开发包或者二进制分发版本。
从AjaxAnywhere官方网站下载最新的开发包,包括jar包--ajaxanywhere-1.1.0.6.jar、js--aa.js文件等。
第二步:获取必要的Javascript文件。
从下载的开发包中获取Javascript文件aa.js,放到Web应用程序根目录中。
第三步:将下载下来的jar包复制到/WEB-INF/lib目录中。
第四步:修改web.xml,添加AAFilter过滤器。
修改部署描述文件web.xml,在该文件中添加AAFilter过滤器。映射部分的部署代码如例程11-22所示。
例程11-22 web.xml添加AAFilter过滤器
<filter>
<filter-name>AjaxAnywhere</filter-name>
<filter-class>org.ajaxanywhere.AAFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AjaxAnywhere</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>AjaxAnywhere</filter-name>
<url-pattern>*.do</url-pattern> <!-- default Struts mapping -->
</filter-mapping>
<filter-mapping>
<filter-name>AjaxAnywhere</filter-name>
<url-pattern>*.htm</url-pattern> <!-- other framewords mapping -->
</filter-mapping>
例程11-22将Web应用程序中的URL以后缀.jsp,do,htm结尾的请求全部有过滤器AAFilter过滤。而在实际项目中,可以根据项目实际需求来修改url-pattern的值,定制要应用AjaxAnywhere的请求类型,即只有特定的请求才应用AjaxAnywhere处理。
AjaxAnywhere的类库及其用法
AjaxAnywhere使用一个名为aa.js的Javascript文件来处理客户端的全部Ajax操作,包括初始化XMLHttpRequest、获取表单内容、发送Ajax请求、执行回调函数等。aa.js也是使用AjaxAnywhere之前必须了解的,至少应该知道其经常用到的API。Ajax Anywhere的官方网站提供了相应的Javascript Document,方便快速查找和了解这些API。
1.AjaxAnywhere的初始化
aa.js中定义了一个AjaxAnywhere对象,针对Ajax的各种操作被抽象成AjaxAnywhere对象的方法,通过这些对象方法完成所需的操作。必要的时候,可以重载这些方法,以便满足个性化的需求。在aa.js文件的末端,AjaxAnywhere对象使用默认的构造方法完成对象实例化。
ajaxAnywhere = new AjaxAnywhere();
ajaxAnywhere.bindById();
所以,所有引用aa.js的页面都可以在Javascript代码段中使用AjaxAnywhere对象的实例ajaxAnywhere。
当AjaxAnywhere初始化的时候,它在默认的构造函数中完成XMLHttpRequest对象的创建,并保存在AjaxAnywhere对象属性req中。AjaxAnywhere对象默认的构造方法如例程11-23所示。
例程11-23 AjaxAnywhere对象的默认构造方法
function AjaxAnywhere() {
this.id = AjaxAnywhere.defaultInstanceName;//id,用于生成更新区域的编号等用途
this.formName = null;//页面表单名称
this.notSupported = false;//是否支持Ajax
this.delayBeforeContentUpdate = true;//在更新页面内容之前是否延迟
this.delayInMillis = 100;//延迟时间
//初始化XMLHttpRequest对象--req
if (window.XMLHttpRequest) {
this.req = new XMLHttpRequest();
} else if (window.ActiveXObject) {
try {
this.req = new ActiveXObject("Msxml2.XMLHTTP");
} catch(e) {
try {
this.req = new ActiveXObject("Microsoft.XMLHTTP");
} catch(e1) {
this.notSupported = true;
/* XMLHTTPRequest not supported */
}
}
}
//确定浏览器是否支持Ajax
if (this.req == null || typeof this.req == "undefined")
this.notSupported = true;
}
2.AjaxAnywhere处理Ajax请求
AjaxAnywhere提供两个公共方法处理Ajax请求的发送:submitAJAX(additionalPost Data, submitButton)和getAJAX(url, zonesToRefresh)。前者用于发送POST类型的Ajax请求,后者则用于发送GET类型的请求,可以直接在Web页面的表单中或者Javascript代码段直接使用ajaxAnywhere.submitAJAX(additionalPostData, submitButton)或者ajaxAny where. getAJAX (url, zonesToRefresh)向服务器发送Ajax请求。
ajaxAnywhere对象的属性formName保存Ajax所指向的表单名称,只要为其指定表单名称(如果未指定,则默认是Web页面中的第一个表单),submitAJAX(additionalPost Data,submitButton)就能够自动获取指定表单的全部表单域及其值,组成parameterName1 =value1 ¶meterName2=value2字符串,这个过程由私有(private)方法preparePostData (submitButton)完成;preparePostData(submitButton)方法遍历表单中的全部元素,将下拉列表、文本框、复选框、单选框等的值自动加入字符串中;submitAJAX方法的参数additionalPostData代表除了表单域值外还要发送给服务器的内容,submitButton则是代表发送操作是否由提交按钮触发的。SubmitAJAX()方法的代码如例程11-24所示。
例程11-24 submitAJAX() 方法发送POST类型请求
AjaxAnywhere.prototype.submitAJAX = function(additionalPostData, submitButton) {
//如果浏览器不支持Ajax
if (this.notSupported)
return this.onSubmitAjaxNotSupported(additionalPostData);
//附加参数为空
if (additionalPostData == null || typeof additionalPostData == "undefined")
additionalPostData = "";
//id绑定
this.bindById();
//获取当前表单对象
var form = this.findForm();
//获取表单的action,确定表单提交目标的url
var actionAttrNode = form.attributes.getNamedItem("action");
var url = actionAttrNode == null?null:actionAttrNode.nodeValue;
//如果表单action未设置,则url为当前页面
if ((url == null) || (url == ""))
url = location.href;
//确定请求成功后要重载刷新的页面区域
var zones = this.getZonesToReload(url, submitButton);
//如果未设置重载刷新区域,则刷新整个页面
if (zones == null) {
if (typeof form.submit_old == "undefined")
form.submit();
else
form.submit_old();
return;
}
//放弃上一次未完成的请求
this.dropPreviousRequest();
//设置请求参数,发送类型为POST,请求为异步方式
this.req.open("POST", url, true);
this.req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
this.req.setRequestHeader("Accept", "text/xml");
//确定要发送给服务器的内容
var postData = this.preparePostData(submitButton);
//已设置要重载刷新的区域,将区域名称附加在发送内容中
if (zones != "")
postData = '&aazones=' + encodeURIComponent(zones) + "&" + postData + "&" + additionalPostData;
else
postData += "&" + additionalPostData;
//发送Ajax请求
this.sendPreparedRequest(postData);
}
显然,如果使用AjaxAnywhere自定义标签为Web页面划分指定了刷新区域,则submitAJAX()方法也会将其包含在参数中发送到服务器端。
相对的,getAJAX(url,zoneToRefresh)方法则比较简单。它获取Ajax请求的目标URL,将需要发送的参数附着在这个URL后面,然后调用XMLHttpRequest对象的open()和send()方法将其发送除去。getAJAX(url,zoneToRefresh)方法的代码如例程11-25所示。
例程11-25 getAJAX()方法发送GET类型请求
AjaxAnywhere.prototype.getAJAX = function(url, zonesToRefresh) {
//如果浏览器不支持Ajax,则刷新整个页面
if (this.notSupported)
return this.onGetAjaxNotSupported(url);
//id绑定
this.bindById();
//如果为设置刷新区域,则刷新整个页面
if (zonesToRefresh == null || typeof zonesToRefresh == "undefined")
zonesToRefresh = "";
var urlDependentZones = this.getZonesToReload(url);
if (urlDependentZones == null) {
location.href = url;
return;
}
//已经设置多个刷新区域
if (urlDependentZones.length != 0)
zonesToRefresh += "," + urlDependentZones;
//放弃上一次未完成的额请求
this.dropPreviousRequest();
//确定请求附加的参数
url += (url.indexOf("?") != -1) ? "&" : "?";
url += "aa_rand=" + Math.random();
// avoid caching
if (zonesToRefresh != null && zonesToRefresh != "")
url += '&aazones=' + encodeURIComponent(zonesToRefresh);
//设置请求参数,发送类型为GET,响应结果为XML文档
this.req.open("GET", url, true);
this.req.setRequestHeader("Accept", "text/xml");
//发送Ajax请求
this.sendPreparedRequest("");
}
与一般的Ajax应用程序一样,AjaxAnywhere更新页面的操作仍然由回调函数完成,这也是Ajax的机制所定义的。应该注意到,submitAJAX()方法和getAJAX()方法的后面都调用了一个sendPreparedRequest()的方法,只是两者传入的参数内容有所不同而已。AjaxAnywhere对象在该方法中设置必要的请求头信息,为XMLHttpRequest对象指定回调函数,然后才将Ajax请求发送出去。setPreparedRequest()方法如例程11-26所示。
例程11-26 setPreparedRequest()方法
AjaxAnywhere.prototype.sendPreparedRequest = function (postData) {
//确定Ajax请求回调函数
var callbackKey = this.id + "_callbackFunction";
if (typeof window[callbackKey] == "undefined")
window[callbackKey] = new Function("AjaxAnywhere.findInstance (\"" + this.id + "\").callback(); ");
this.req.onreadystatechange = window[callbackKey];
//显示请求正在处理的提示信息
this.showLoadingMessage();
//设置请求头参数,当前请求为aaxml请求
this.req.setRequestHeader("aaxmlrequest", "true");
//发送请求
this.req.send(postData);
}
从这个方法可以看出,如果未在Web页面中定义相应的回调函数,则AjaxAnywhere将使用默认的回调函数。
AjaxAnywhere统一使用XML文档来组织服务器返回的响应数据。这个文档采用UTF-8的编码方式,例程11-22所配置的AAFilter也采用UTF-8的方式从请求中获取请求数据。AjaxAnywhere支持页面区域内容刷新、URL跳转、脚本、图像等处理功能,这些处理功能的信息都包含在这个XML文档中。当客户端发送的Ajax请求被正常执行后,AjaxAnywhere即将返回的响应数据组织为符合例程11-27所示文档类型定义文件DTD所规定范式的XML文档。
例程11-27 AjaxAnywhere返回的XML文档的文档类型定义DTD
<?xml version="1.0" encoding="UTF-8" ?>
<!ELEMENT zones ( document*, zone*, script*, exception*, redirect*, image* ) >
<!ELEMENT document (#PCDATA)>
<!ELEMENT zone ( #PCDATA ) >
<!ATTLIST zone name NMTOKEN #REQUIRED >
<!ELEMENT script ( #PCDATA ) >
<!ELEMENT exception ( #PCDATA ) >
<!ATTLIST exception type NMTOKEN #REQUIRED >
<!ELEMENT redirect ( #PCDATA ) >
<!ELEMENT image (#PCDATA) >
例程11-28是一个仅包含zone,script,exception和redirect节点的示范XML文档。这个文档由AjaxAnywhere的业务类自动组织,与Web应用程序的其他实体类、业务类无关。Web应用程序只需要按照传统的通信机制一样,将响应结果输出即可。
例程11-28 AjaxAnywhere返回的包含响应数据的XML文档
<?xml version="1.0" encoding="UTF-8"?>
<zones>
<zone name="stateSavingScript"/>
<zone name="countriesList">
<![CDATA[
<select size="10" name="country">
<option value=IN>India</options>
</select>
]]>
</zone>
<script>
<![CDATA[
var states = document.getElementsByName("jsf_state_64")
var trees = document.getElementsByName("jsf_tree_64")
if(states!=null)
for(var i=0;i<states.length;i++)
if(states[i].tagName.toLowerCase()=="input") {
states[i].values="null";
}
if(trees!=null)
for(var i=0;i<trees.length;i++)
if(trees[i].tagName.toLowerCase()=="input")
trees[i].values="null";
]]>
</script>
<script/>
<script/>
<exception type="org.apache.jasper.JasperException"><![CDATA[
org.apache.jasper.JasperException:AjaxAnywhere demo exception
at org.apache.jasper.servlet.JspServletWraper.service (Jsp Servlet Wrapper.java:372)
............
]]>
</exception>
<redirect><![CDATA[reditected.jsp]]></redirect>
</zones>
AjaxAnywhere默认的回调函数使用XMLHttpRequest对象的responseXML()方法来获取服务器返回的这个XML文档,使用DOM解析。如果XML文档包含document和zone元素,则按照之前设定的更新区域来更新页面中指定区域的内容。如果XML文档中包含script元素,则从元素中提取脚本,使用eval()方法执行。如果服务器响应请求的时候发生系统异常或者HTTP请求异常,则XML文档中会包含exception元素,回调函数即可从元素中获取异常信息,交给this.handleException (type, details)方法做异常处理。如果XML文档中包含redirect元素,则回调函数将其转化为“locarion.href=newURL”的方法,将页面跳转到指定的URL。如果XML文档中包含image元素,则AjaxAnywhere即从服务器获取image对象所指定的图像,将其缓存在浏览器。AjaxAnywhere默认的回调函数如例程11-29所示。
例程11-29 AjaxAnywhere对象默认的构造函数
AjaxAnywhere.prototype.callback = function() {
if (this.req.readyState == 4) {
this.onBeforeResponseProcessing();
this.hideLoadingMessage();
if (this.req.status == 200) {
if (this.req.getResponseHeader('content-type').toLowerCase(). substring(0, 8) != 'text/xml')
alert("AjaxAnywhere error : content-type in not text/xml : [" + this.req.getResponseHeader('content-type') + "]");
var docs = this.req.responseXML.getElementsByTagName("documen t");
var redirects = this.req.responseXML.getElementsByTagNa me ("redirect");
var zones = this.req.responseXML.getElementsByTagName("zon e");
var exceptions = this.req.responseXML.getElementsByTagName ("exception");
var scripts = this.req.responseXML.getElementsByTagName("scr ipt");
var images = this.req.responseXML.getElementsByTagName("imag e");
if (redirects.length != 0) {
var newURL = redirects[0].firstChild.data;
location.href = newURL;
}
if (docs.length != 0) {
var newContent = docs[0].firstChild.data;
//cleanup ressources
delete this.req;
document.close();
document.write(newContent);
document.close();
}
if (images.length != 0) {
var preLoad = new Array(images.length);
for (var i = 0; i < images.length; i++) {
var img = images[i].firstChild;
if (img != null) {
preLoad[i] = new Image();
preLoad[i].src = img.data;
}
}
if (this.delayBeforeContentUpdate) {
delay(this.delayInMillis);
}
}
if (zones.length != 0) {
for (var i = 0; i < zones.length; i++) {
var zoneNode = zones[i];
var name = zoneNode.getAttribute("name");
var fc = zoneNode.firstChild;
var html = (fc == null)?"":fc.data;
var zoneHolder = document.getElementById("aazone." + name);
if (zoneHolder != null && typeof(zoneHolder) != "undefined") {
zoneHolder.innerHTML = html;
}
}
}
if (exceptions.length != 0) {
var e = exceptions[0];
var type = e.getAttribute("type");
var stackTrace = e.firstChild.data;
this.handleException(type, stackTrace);
}
if (scripts.length != 0) {
for (var $$$$i = 0; $$$$i < scripts.length; $$$$i++) {
// use $$$$i variable to avoid collision with "i" inside user script
var script = scripts[$$$$i].firstChild;
if (script != null) {
script = script.data;
if (script.indexOf("document.write") != -1) {
this.handleException("document.write", "This script contains document.write(), which is not compatible with AjaxAnywhere : \n\n" + script);
} else {
eval(script);
}
}
}
var globals = this.getGlobalScriptsDeclarationsList(scr ipt);
if (globals != null)
for (var i in globals) {
var objName = globals[i];
try {
window[objName] = eval(objName);
} catch(e) {
}
}
}
} else {
if (this.req.status != 0)
this.handleHttpErrorCode(this.req.status);
}
this.restoreSubstitutedSubmitButtons();
this.onAfterResponseProcessing();
}
}
值得注意的是,在例程11-29所示的默认回调函数中,除了解析XML文档外,在回调函数执行业务逻辑之前和之后,还分别调用了两个可供重载的方法:this.onBeforeResp onse Processing() 和 this.onAfterResponseProcessing()。如果希望在执行回调函数更新页面内容之前处理额外的业务,则可以在适当的位置重载this.onBeforeResponseProcessing()方法。如果希望执行完回调函数更新页面内容之后,还希望继续执行其他逻辑操作,则可以在适当的位置重载this.onAfterResponseProcessing()方法。从aa.js的源码中,可以看到目前这两个方法都未执行任何操作,如例程11-30所示。
例程11-30 onBeforeResponseProcessing()和onAfterResponseProcessing()方法
/**
* Override this method to implement a custom action
*/
AjaxAnywhere.prototype.onBeforeResponseProcessing = function () {
};
/**
* Override this method to implement a custom action
*/
AjaxAnywhere.prototype.onAfterResponseProcessing = function () {
};
3.AjaxAnywhere处理系统异常和HTTP请求异常
在Web应用程序中,系统异常和HTTP请求异常的处理一向是件比较头疼的事情。在Ajax应用程序中,这两个异常的处理会比传统的通信机制下相对棘手,惟一比较有效的方式就是在回调函数中判断HTTP请求的状态码并做相应的处理。如果异常未加以处理,用户根本不知道请求到底执行成功没有,页面上也不会有任何的反应,不像传统的通信机制下会显示“HTTP404错误”等类似的错误页面。
比较可喜的是,AjaxAnywhere提供了一种比较方便的异常处理方式。之前提到的,AjaxAnywhere将服务器返回的响应数据包装成一个XML文档,这个XML文档中同样也包含系统异常和HTTP请求异常的信息,它们被封装在exception元素中。在AjaxAnywhere默认的回调函数中可以看到,它将系统异常的信息交由this.handleException (type,detail)方法处理,而HTTP请求异常则交由this. handleHttpErrorCode(code)方法处理。默认的this.handle Exception(type,detail)方法将系统异常的细节显示在弹出窗口中,如图11-22所示,其代码如例程11-31所示。
例程11-31 AjaxAnywhere处理系统异常的方法
AjaxAnywhere.prototype.handleException = function(type, details) {
alert(details);
}
图11-22 AjaxAnywhere显示的系统异常信息
而默认的this.handleHttpErrorCode(code)则允许用户在一个新的页面中显示HTTP请求异常信息,如图11-23所示,其代码如例程11-32所示。
例程11-32 AjaxAnywhere处理HTTP请求异常的方法
AjaxAnywhere.prototype.handleHttpErrorCode = function(code) {
var details = confirm("AjaxAnywhere default error handler. XMLHttp Request HTTP Error code:" + code + " \n\n Would you like to view the response content in a new window?");
if (details) {
var win = window.open("", this.id + "_debug_window");
if (win != null) {
win.document.write("<html><body><xmp>" + this.req.response Text);
win.document.close();
win.focus();
} else {
alert("Please, disable your pop-up blocker for this site fir st.");
}
}
}
图11-23 AjaxAnywhere显示的HTTP请求异常
如果用户希望系统提供更加人性化的系统异常和HTTP异常处理机制,则可以重载这两个异常处理方法。AjaxAnywhere的demo示范包中有相应的案例可供参考,如图11-24和图11-25所示。
图11-24 重载后的系统异常处理
图11-25 重载后的HTTP请求异常处理
4.定制Ajax请求执行的提示信息
之前说过,在Ajax应用程序中,当Ajax请求正在执行的时候,应当在页面的适当位置提示用户请求正在执行。而Ajax请求执行完毕后,应当提示用户页面已经更新。AjaxAnywhere提供了默认的解决方案,在页面右上角显示一个“Loading…”的蓝色提示条,如图11-26所示,其实质是一个固定位置的DIV浮动层。
图11-26 AjaxAnywhere默认的Ajax请求执行提示信息
AjaxAnywhere对象的方法showLoadingMessage()和hideLoadingMessage()用于显示和隐藏这个提示信息,它们分别在Ajax请求发送前和回调函数中被调用,其代码如例程11-33所示。
例程11-33 AjaxAnywhere默认的Ajax请求执行提示信息方法
AjaxAnywhere.prototype.showLoadingMessage = function() {
var div = document.getElementById("AA_" + this.id + "_loading_ div");
if (div == null) {
div = document.createElement("DIV");
document.body.appendChild(div);
div.id = "AA_" + this.id + "_loading_div";
div.innerHTML = " Loading...";
div.style.position = "absolute";
div.style.border = "1 solid black";
div.style.color = "white";
div.style.backgroundColor = "blue";
div.style.width = "100px";
div.style.heigth = "50px";
div.style.fontFamily = "Arial, Helvetica, sans-serif";
div.style.fontWeight = "bold";
div.style.fontSize = "11px";
}
div.style.top = document.body.scrollTop + "px";
div.style.left = (document.body.offsetWidth - 100 - (document.all? 20:0)) + "px";
div.style.display = "";
}
AjaxAnywhere.prototype.hideLoadingMessage = function() {
var div = document.getElementById("AA_" + this.id + "_loading_ div");
if (div != null)
div.style.display = "none";
}
在必要的时候,可以在页面的适当位置重载上述两个方法,提供个性化的提示信息。例程11-34重载上述两个方法,将这个提示信息替换成轮显的图片,如图11-27所示。读者可以在AjaxAnywhere的demo演示包中找到这个案例。
例程11-34 重载后的Ajax请求提示信息方法
ajaxAnywhere.showLoadingMessage = function() {
var img = document.getElementById("myImg");
if (img == null) {
img = document.createElement("img");
document.body.appendChild(img);
img.id = "myImg";
img.src = "balls.gif";
img.style.position = "absolute";
img.style.border = "1 solid black";
img.style.top = 0;
img.style.left = document.body.offsetWidth - 170;
}
img.style.display = "";
}
AjaxAnywhere.prototype.hideLoadingMessage = function() {
var img = document.getElementById("myImg");
if (img != null)
img.style.display = "none";
}
图11-27 重载后的Ajax请求提示信息
5.设置页面可刷新区域
AjaxAnywhere使用自定义标签<aa:zone>来划分页面区域,从而动态地指定页面可刷新区域。通过这种方法,只需要在页面适当位置中添加<aa:zone name=""></aa:zone>标签。对于已有的Web应用程序,几乎无须更改原有的代码,只须使用<aa:zone>标签指定更新区域。AjaxAnywhere会将<aa:zone>标签解析为<span id=""></span>的标记,并最终通过更新其innerHTML属性值来达到更新页面的目的。
区域划分好之后,需要告诉AjaxAnywhere哪些区域需要更新,即设置页面可刷新区域。AjaxAnywhere提供两种方式设置页面可刷新区域:客户端重载AjaxAnywhere对象的getZonesToReload()方法,或者服务器端调用AAUtil类的addZonesToRefresh(ServletReq uest request, String commaSeparatedZonesList)方法。
如果使用客户端重载的方式,则需要将<aa:zone name=""></aa:zone>所指定区域的name属性值组织成以逗号“,”分隔的字符串。例程11-35根据区域内的复选框选中情况来确定该区域是否可刷新。
例程11-35 重载AjaxAnywhere对象的getZonesToReload()方法
ref_All = false;
ajaxAnywhere.getZonesToReload = function (url){
if (ref_All)
return "document.all";
var zones="";
var form = this.findForm();
for (var i=0;i<form.elements.length;i++){
var el = form.elements[i];
if (el.type=="checkbox" && el.checked)
zones += el.value+",";
}
return zones;
}
如果使用服务器端设置的方式,则需要从request中或者其他地方获取指定的zone名称,调用AAUtil类的addZonesToRefresh(ServletRequest request, String commaSeparated ZonesList)并逐个将其保存。当然,在此之前应该将要刷新区域的名称以“zones=zoneNa me1,zoneName2”的形式附加在请求中。例程11-36展示了这一过程。
例程11-36 调用AAUtil类的方法保存可刷新区域
<%
if (AAUtils.isAjaxRequest(request)) {
String[] commaSeparatedZones = request.getParameterValues ("zones");
for (int i = 0; commaSeparatedZones != null && i < commaSeparated Zones.length; i++) {
String zone = commaSeparatedZones[i];
AAUtils.addZonesToRefresh(request, zone);
}
}
%>
这两个案例也都可以在AjaxAnywhere提供的demo演示包中找到。有兴趣的读者可以自行查阅相关代码