分类: Java
2008-04-11 21:42:55
作为一个Ajax开发框架,Prototype对 Ajax开发提供了有力的支持。在Prototype中,与Ajax相关的类和对象包括:Ajax、Ajax.Responsders、 Ajax.Base、Ajax.Request、Ajax. PeriodicalUpdater和Ajax.Updater,图2-3所示为这些类和对象之间的关系及其常用属性和方法,下面分别对这些类和对象进行 介绍。
图2-3 Prototype中Ajax相关类和对象关系示意图
Ajax对象为其他的Ajax功能类提供了最基本的 支持,它的实现如2.2.7节中例2-10所示,其中包括一个方法getTransport和一个属性activeRequestCount。 getTransport方法返回一个XMLHttpRequest对象,activeRequestCount属性代表正在处理中的Ajax请求的个 数。
Ajax.Base类是Ajax.Request类和Ajax.PeriodicalUpdater类的基类。它提供了3个方法:
l setOptions:设置Ajax操作所使用的选项。
l responseIsSuccess:判断Ajax操作是否成功。
l responseIsFailure:判断Ajax操作是否失败(与responseIsSuccess相反)。
Ajax.Base类的主要作用是提取出一些公用的方法,其他类通过继承的方式使用这些方法,实现代码复用。
这是Prototype中最经常使用的一个Ajax 相关类。Ajax.Request类的方法通常是内部使用的,因此这里就不一一列举,有兴趣的读者可以参考Prototype的源代码。这里重点讲讲如何 使用Ajax.Request类,首先给出一个最简单的Ajax.Request类的应用示例,如例2-11所示,注意示例中的黑体字。
例2-11 Ajax.Request类应用示例
Ajax.Request测试页面:
"">
function test() {
// 创建Ajax.Request对象,发起一个Ajax请求
var myAjax = new Ajax.Request(
'data.html', // 请求的URL
{
method: 'get', // 使用GET方式发送HTTP请求
onComplete: showResponse // 指定请求成功完成时需要执行的方法
}
);
}
function showResponse(response) {
$('divResult').innerHTML = response.responseText;
}
data.html:
Ajax.Request对象在初始化时需要提供两 个参数:第1个参数是将要请求页面的URL,这里使用的data.html是一个普通的HTML静态页面;第2个参数是Ajax操作的选项,在 Prototype中并没有专门为Ajax操作选项定义一个类,通常都是像例2-11这样,通过匿名对象的方式设置Ajax操作的参数。在例2-11中, Ajax操作选项具有两个属性:method表示HTTP请求方式,默认是POST方式;onComplete指定了Ajax操作完成以后(即 XMLHttpRequest对象的status属性为4时),页面将要执行的函数。当然,Ajax操作还包括很多其他选项,如表2-1所示。
表2-1 Ajax操作选项属性含义
属性名称 |
含义 |
method |
HTTP请求方式(POST/GET/HEAD)。 |
parameters |
在HTTP请求中传入的URL格式的值列表,即URL串中问号之后的部分。 |
asynchronous |
是否做异步XMLHttpRequest请求。 |
postBody |
在POST请求方式下,传入请求体中的内容。 |
requestHeaders |
和请求一起被传入的HTTP头部列表,这个列表必须含有偶数个项目,因为列表中每两项为一组,分别代表自定义部分的名称和与之对应的字符串值。 |
onXXXXXXXX |
在HTTP 请求、响应的过程中,当XMLHttpRequest对象状态发生变化时调用的响应函数。响应函数有5个:onUninitialized、 onLoading、onLoaded、onInteractive和onComplete。传入这些函数的参数可以有2个,其中第1个参数是执行 HTTP请求的XMLHttpRequest对象,第2个参数是包含被执行的X-JSON响应的HTTP头。 |
onSuccess |
Ajax操作成功完成时调用的响应函数,传入的参数与onXXXXXXXX相同。 |
onFailure |
Ajax操作请求完成但出现错误时调用的响应函数,传入的参数与onXXXXXXXX相同。 |
onException |
Ajax操作发生异常情况时调用的响应函数,它可以接收2个参数,其中第1个参数是执行HTTP请求的XMLHttpRequest对象,第2个参数是异常对象。 |
例2-11使用Ajax.Request类实现了页 面的局部刷新效果,而这样类似的功能在Ajax应用中是经常使用的。因此,为了简化这种工作,Prototype框架从Ajax.Requet类中派生出 一个子类——Ajax.Updater。与Ajax.Request相比,Ajax.Updater的初始化多了一个container参数,该参数代表 将要更新的页面元素的id。例2-11的功能通过Ajax.Updater的实现,会变得更加简单,如例2-12所示。
例2-12 Ajax.Updater类的应用示例
"">
function test() {
var myAjax = new Ajax.Updater(
'divResult', // 更新的页面元素
'data.html', // 请求的URL
{
method: 'get'
}
);
}
此外,Ajax.Updater类还有另外一个功 能,如果请求的页面内容中包括JavaScript脚本,Ajax.Updater类可以执行其中的脚本,只需要在Ajax操作选项中增加属性 “evalScripts: true”即可。对例2-11中的data.html进行修改,在其中加入JavaScript脚本,如例2-13所示。
例2-13 data.html
sayHi = function() {
alert("Hello, " + $F('name') + "!");
}
调用Ajax.Updater的JavaScript脚本修改为:
function test() {
var myAjax = new Ajax.Updater(
'divResult', // 更新的页面元素
'data.html', // 请求的URL
{
method: 'get',
evalScripts: true
}
);
}
这样就可以使用data.html页面的内容更新当前页面中的
这里需要注意的是例2-13中sayHi函数的写法,如果写成
function sayHi() {
alert("Hello, " + $F('name') + "!");
}
或者
var sayHi = function() {
alert("Hello, " + $F('name') + "!");
}
程序是不能正常运行的。这是因为 Ajax.Updater执行脚本是通过eval的方式,而不是将脚本内容引入到当前页面,直接声明的function sayHi或者用var声明的sayHi函数,其作用域只是在这段脚本内部,外部的其他脚本不能访问sayHi函数。而按照例2-13的方式声明的函数, 其作用域是整个window。
和Ajax.Request类相似, Ajax.PeriodicalUpdater类也继承自Ajax.Base类。在一些Ajax应用中,需要周期性地更新某些页面元素,例如天气预报、即 时新闻等等。实现这样的功能通常要使用JavaScript中的定时器函数setTimeout、clearTimeout等,而有了 Ajax.PeriodicalUpdater类可以很好地简化这类编码工作。
新建一个Ajax. PeriodicalUpdater类的实例需要指定3个参数:
l container:将要更新的页面元素id;
l url:请求的URL地址;
l options:Ajax操作选项。
和Ajax.Updater类相似,Ajax.PeriodicalUpdater类也支持动态执行JavaScript脚本,只需在Ajax操作选项中增加(evalScripts: true)属性值即可。
Ajax.PeriodicalUpdater类支 持两个特殊的Ajax操作选项:frequency和decay。frequency参数很容易理解,既然是定时更新页面元素,或者定时执行脚本,那么多 长时间更新或者执行一次呢?frequency指的就是两次Ajax操作之间的时间间隔,单位是秒,默认值为2秒。
如果仅指定frequency参数,程序会按照固定 的时间间隔执行Ajax操作。这样的更新策略合理吗?答案取决于请求URL中数据的更新频率。如果请求的数据会很有规律地按照固定频率改变,那么只要设置 一个合适的frequency值,就可以很有效地实现页面的定时更新。然而实际应用中的数据往往不会那么理想,例如新闻,可能在一天中只有特定的一段时间 更新频率会很高,而在其他时间则几乎没有变化。经常遇到这样的情况该怎么办呢?Ajax.PeriodicalUpdater类支持的decay属性就是 为了解决这个问题而产生的。当option中带有decay属性时,如果请求返回的数据与上次相同,那么下次进行Ajax操作的时间间隔会乘以一个 decay的系数。
为了比较明显地看到decay属性的效果,在请求的测试页面中加入记录时间的脚本,代码如例2-14所示。
例2-14 Ajax.PeriodicalUpdater类应用示例
ex10.html:
"">
var count = 0;
function test() {
var myAjax = new Ajax.PeriodicalUpdater(
'divResult', // 定时更新的页面元素
'script1.html', // 请求的URL
{
method: 'get', // HTTP请求的方式为GET
evalScripts: true, // 是否执行请求页面中的脚本
frequency: 1, // 更新的频率
decay: 2 // 衰减系数
}
);
}
script1.html:
// Ajax.PeriodicalUpdater调用函数计数
count++;
// 在
// Ajax.PeriodicalUpdater的调用次数
var str = $('divResult2').innerHTML;
$('divResult2').innerHTML
= str + "count = " + count + ": " + new Date() +
"
";
例2-14的运行结果如图2-4所示。
图2-4 Ajax.PeriodicalUpdater类应用示例
可以看到,由于请求返回的数据一直没有发生变化,每次请求时间的间隔是上一次的2倍(decay=2)。如果某一次请求返回的数据发生了变化,那么执行请求的时间间隔则恢复到初始值。
Ajax.Responders对象维护了一个正在 运行的Ajax对象列表,在需要实现一些全局的功能时就可以使用它。例如,在Ajax请求发出以后需要提示用户操作正在执行中,而操作返回以后则取消提 示。利用Ajax.Responders对象就可以实现这样的功能,如例2-15所示。
例2-15 Ajax.Responders对象应用示例
"">
function test() {
var myAjax = new Ajax.Request(
'data.html',
{
method: 'get',
onComplete: showResponse
}
);
}
function showResponse(response) {
$('divResult').innerHTML = response.responseText;
}
var handle = {
onCreate: function() {
Element.show('loading'); // 当创建Ajax请求时,显示loading
},
onComplete: function() {
// 当请求成功返回时,如果当前没有其他正在运行中的Ajax请求,隐藏loading
if (Ajax.activeRequestCount == 0) {
Element.hide('loading');
}
}
};
// 将handle注册到全局的Ajax.Responders对象中,使其生效
Ajax.Responders.register(handle);
例2-15中定义了一个handle对象,其中包含onCreate和onComplete函数。页面中发出任何一个Ajax请求时都会调用onCreate方法,而请求完成时都会调用onComplete方法。例2-15的运行结果如图2-5所示。
图2-5 Ajax.Responders对象应用示例
通过这个JS类库,将很容易的应用AJAX技术
ajax.updater应用
new Ajax.Updater('id',"url",{options});
id:你要更新的目标id
url:你要执行的操作,也可以是cgi
options:
属性 类型 默认 描述
method Array 'post' HTTP 请求方式。
parameters String '' 在HTTP请求中传入的url格式的值列表。
asynchronous Boolean true 指定是否做异步 AJAX 请求。
postBody String undefined 在HTTP POST的情况下,传入请求体中的内容。
requestHeaders
Array undefined 和请求一起被传入的HTTP头部列表, 这个列表必须含有偶数个项目,
任何奇数项目是自定义的头部的名称,接下来的偶数项目使这个头部项目的字符串值。 例子:['my-header1', 'this is the
value', 'my-other-header', 'another value']
onXXXXXXXX
Function(XMLHttpRequest) undefined 在AJAX请求中,当相应的事件/状态形成的时候调用的自定义方法。 例如
var myOpts = {onComplete: showResponse, onLoaded: registerLoaded};.
这个方法将被传入一个参数, 这个参数是携带AJAX操作的 XMLHttpRequest对象。
onSuccess Function(XMLHttpRequest) undefined 当AJAX请求成功完成的时候调用的自定义方法。 这个方法将被传入一个参数, 这个参数是携带AJAX操作的 XMLHttpRequest对象。 字串6
简单例子:
一:
index.html:
ajax.html
说明:为了使ajax.html中test()方法运行,首先必须设定evalScripts:true,其次在test函数的命名方式修改为“函数名字=function()”的方式。另外也可以将js之前放至index.html也能运行,不需要修改函数。
二:
表单的提交可以无刷新的方式
图2-1 $A函数应用示例
例2-4是通过点击“Show the options”按钮触发onclick事件的响应函数showOptions,函数showOptions使用$A方法将lstFramework 的option对象集合转换为数组输出,相应的输出结果如图2-1所示。
$F()是另一个经常使用的快捷方式,它是 Form.Element.getValue()函数的缩写。$F()函数用来求得页面中输入控件的输入值,它的输入参数可以是目标控件的id值,也可以 是目标控件对象本身。$F支持的输入控件包括系列(即type=submit / hidden / password / text / checkbox / radio)、下拉列表
例2-5 $F()函数应用示例
"">
function test() {
alert($F("userName"));
}
Hash对象Prototype中定义了Hash对 象一个用于模拟Hash数据结构,$H()函数的功能是将对象转换为Hash对象。$H函数将Hash对象的方法和属性通过Object.extend方 法扩展到目标对象上,这样返回的对象就具有了Hash对象的方法,如keys方法,values方法等等。下面是$H()函数的一个应用示例:
function test() {
// 创建一个对象
var obj = {
key1: 1,
key2: 2,
key3: 3
};
// 将其转换为Hash对象
var hash = $H(obj);
alert(hash.toQueryString());
}
$R()函数是new ObjectRange(start, end, exclusive)的缩写形式,它根据指定的起始边界返回相应的对象范围。在Prototype中$R()函数的定义如例2-6所示。
例2-6 $R()函数定义
ObjectRange = Class.create();
Object.extend(ObjectRange.prototype, Enumerable);
Object.extend(ObjectRange.prototype, {
initialize: function(start, end, exclusive) {
this.start = start;
this.end = end;
this.exclusive = exclusive;
},
_each: function(iterator) {
var value = this.start;
do {
iterator(value);
value = value.succ();
} while (this.include(value));
},
// include函数的作用是判断value是否包含在对象范围之内
include: function(value) {
if (value < this.start)
return false;
if (this.exclusive) // 注意exclusive参数仅在判断上界是有效
return value < this.end;
return value <= this.end;
}
});
var $R = function(start, end, exclusive) {
// 定义$R方法,$R是new ObjectRange(start, end, exclusive)的一个简单写法或快捷方式
return new ObjectRange(start, end, exclusive);
}
可以看到,ObjectRange类是由 Enumerable类继承而来,它的初始化参数start、end和exclusive分别代表ObjectRange对象的下界、上界以及是否排除上 界的值。这里需要注意的是,exclusive参数仅仅对上界起作用,从ObjectRange的include方法的实现代码中不难看出这一点。例2- 7给出了$R()函数的应用示例,其中比较了exclusive参数分别为true和false时的区别。
例2-7 $R()函数应用示例
"">
// 依次输出1,2,3,4
function test_R1(){
var range = $R(1, 5, true);
range.each(function(value, index){
alert(value);
});
}
// 依次输出1,2,3,4,5
function test_R2(){
var range = $R(1, 5, false);
range.each(function(value, index){
alert(value);
});
}
$$()函数是Prototype 1.5新增的一个快捷方式,它允许开发人员通过CSS样式选择页面中的元素。熟悉XPath的读者会发现,CSS选择符在语法形式上和XML文档的XPath十分类似,Prototype支持的CSS选择符包括以下几种类型:
l 元素标签名称,例如:$$(“li”)。
l 元素ID,例如:$$(“#fixtures”)。
l CSS类名,例如:$$(“.first”)。
l 元素是否具有某个属性,例如:$$(“h1[class]”)。
l 元素的某个属性是否符合特定的条件,例如:$$('a[href="#"]')、$$('a[class~="internal"]')、$$('a[href!=#]')。
l 上面所有这些CSS选择符的类型可以自由组合,形成一个复合的CSS选择符,例如:$$('li#item_3[class][href!="#"]')。
l 不同的CSS选择符(包括复合CSS选择符)之间用空格分隔,就组成了一个多层的CSS选择符,它通过指定目标元素的父节点甚至更多层父节点的CSS样式属性来定位目标元素。例如:$$('div[style] p[id] strong')。
例2-8给出了一个$$()函数的测试页面示例,读者可以在该页面中输入不同的CSS选择符表达式,测试结果。
例2-8 $$()函数测试页面
"">
/*
#testcss1 { font-size:11px; color: #f00; }
#testcss2 { font-size:12px; color: #0f0; display: none; }
/* ]]> */
function test() {
// 根据输入的CSS选择符,切换相应元素的显示
$$($F('csspath')).each(
function(item) {
Element.toggle(item);
}
);
}
例2-8的运行页面如图2-2所示,在文本输入框中输入一个CSS选择符(例如“.title”),点击“click”按钮即可切换相应的页面元素(即Some title here)的显示/隐藏状态。
(a) 在文本输入框中输入CSS选择符“.title” (b) 页面元素“Some title here”隐藏
图2-2 $$函数应用示例
在程序开发的过程中有时会遇到这样的情况:在若干个函数中开发人员不能确定哪一个会返回正确的结果,只能依次尝试。Prototype中Try.these()函数为开发人员提供了一个很简便的方式来解决类似的问题。Try.these()函数的的定义如例2-9所示。
例2-9 Try.these()函数
var Try = {
these: function() {
// 返回结果
var returnValue;
for (var i = 0; i < arguments.length; i++) {
// 输入参数为多个function对象
var lambda = arguments[i];
try {
// 如果其中一个函数成功返回,则返回该函数的结果
returnValue = lambda();
break;
} catch (e) {}
}
return returnValue;
}
}
从上述代码中可以看到,Try.these()函数 的每一个参数都必须是一个无参的JavaScript方法。在Prototype框架中,实现Ajax对象的getTransport方法就用到了 Try.these()函数,getTransport方法的作用是返回一个XMLHttpRequest对象,而在不同浏览器中创建 XMLHttpRequest对象的方式是不同的。通过Try.these ()函数可以依次尝试各种浏览器创建XMLHttpRequest对象的方法,直到成功为止。例2-10所示为Ajax对象的getTransport方 法的实现代码。
例2-10 Ajax对象的getTransport方法的实现代码
var Ajax = {
getTransport: function() {
// 尝试以下3种创建XMLHttpRequest对象的方法
// 1. Mozilla浏览器中的XMLHttpRequest对象
// 2. 创建ActiveX对象"Msxml2.XMLHTTP"
// 3. 创建ActiveX对象"Microsoft.XMLHTTP"
return Try.these(
function() {return new XMLHttpRequest()},
function() {return new ActiveXObject('Msxml2.XMLHTTP')},
function() {return new ActiveXObject('Microsoft.XMLHTTP')}
) || false;
},
// 当前活动的Ajax请求计数
activeRequestCount: 0
}
第2章介绍了创建XMLHttpRequest对象的方法,代码中对浏览器的类型、版本进行了判断,最终返回XMLHttpRequest对象的实例。与第2章中使用的方法相比,Prototype框架中Ajax对象的实现代码更加简洁明了。