原文地址:
http://www.joehewitt.com/software/firebug/docs.php
FireBug 是一个非常实用的JavaScript以及DOM查看调试工具,是 Firefox 的一个插件。使用 FireBug 调试 AJAX 应用非常方便,终于可以告别 alert 时代了!
Console Logging 函数
FireBug 为所有 Web 页面提供了一个 console 对象。这个对象有以下函数:
Logging 基础
console.log("message" [,objects]) - 将一个字符串打印到控制台。字符串可以包含任何“String Formatting”小节描述的模式。字符串后面的对象应该用来取代之前字符串中的模式。(译者注:大家用过C里面 printf 吧,效果基本是一样的。)
Logging 等级
通常根据不同的等级来区分Logging的严重程度是很有帮助的。FireBug 提供了4个等级。为了达到视觉分离的效果,这些函数与 log
不同的地方就是它们在被调用的时候会自动包含一个指向代码行数的链接。
console.debug("message" [,objects]) - 记录一个 debug 消息。
console.info("message" [,objects]) - 记录一个信息.
console.warn("message" [,objects]) - 记录一个警告.
console.error("message" [,objects]) - 记录一个错误.
断言
断言是一条确保代码规则的非常好的途径。console 对象包含了一系列各种类型的断言函数,并且允许你编写自己的断言函数。
console.assert(a, "message" [,objects]) - Asserts that an
a
is true.
console.assertEquals(a, b, "message" [,objects]) - Asserts that
a
is equal to
b
.
console.assertNotEquals(a, b, "message" [,objects]) - Asserts that
a
is not equal to
b
.
console.assertGreater(a, b, "message" [,objects]) - Asserts that
a
is greater than
b
.
console.assertNotGreater(a, b, "message" [,objects]) - Asserts that
a
is not greater than
b
.
console.assertLess(a, b, "message" [,objects]) - Asserts that
a
is less than
b
.
console.assertNotLess(a, b, "message" [,objects]) - Asserts that
a
is not less than
b
.
console.assertContains(a, b, "message" [,objects]) - Asserts that
a
is in the array
b
.
console.assertNotContains(a, b, "message" [,objects]) - Asserts that
a
is not in the array
b
.
console.assertTrue(a, "message" [,objects]) - Asserts that
a
is equal to
true
.
console.assertFalse(a, "message" [,objects]) - Asserts that
a
is equal to
false
.
console.assertNull(a, "message" [,objects]) - Asserts that
a
is equal to
null
.
console.assertNotNull(a, "message" [,objects]) - Asserts that
a
is not equal to
null
.
console.assertUndefined(a, "message" [,objects]) - Asserts that
a
is equal to
undefined
.
console.assertNotUndefined(a, "message" [,objects]) - Asserts that
a
is not equal to
undefined
.
console.assertInstanceOf(a, b, "message" [,objects]) - Asserts that
a
is an instance of type
b
.
console.assertNotInstanceOf(a, b, "message" [,objects]) - Asserts that
a
is not an instance of type
b
.
console.assertTypeOf(a, b, "message" [,objects]) - Asserts that the type of
a
is equal to the string
b
.
console.assertNotTypeOf(a, b, "message" [,objects]) - Asserts that the type of
a
is not equal to the string
b
.
测量(Measurement)
下面的一些函数可以让你方便的测量你的一些代码。
console.trace() - 记录执行点的堆栈信息。
console.time("name") - 根据 name 创建一个唯一的计时器。
console.timeEnd("name") - 根据 name 停止计时器,并且记录消耗的时间,以毫秒为单位。
console.count("name") - 记录该行代码执行的次数。
字符串格式化
所有 console 的 logging 函数都可以通过以下模式格式化字符串:
%s - 将对象格式化为字符串。
%d, %i, %l, %f - 将对象格式化为数字。
%o - 将对象格式化成一个指向 inspector 的超链接。
%1.o, %2.0, etc.. - 将对象格式化成包含自己属性的可交互的表格。
%.o - 将对象格式化成具有自身属性的一个数组。
%x - 将对象格式化成一个可交互的 XML 树形结构。
%1.x, %2.x, etc.. - 将对象格式化成一个可交互的 XML 数型结构,并且展开
n 层节点。
如果你需要一个真实的 % 符号,你可以通过一个转移符号就像这样 "/%"。
命令行函数
内建的命令行函数可以通过以下命令行使用:
$("id") - document.getElementById() 的简写。(译者注:跟 prototype.js 学来的吧?)
$$("css") - 返回一个符合 CSS 选择器的元素数组。
$x("xpath") - 返回一个符合 XPath 选择器的元素数组。
$0 - 返回最近被检查(inspected)的对象。
$1 - 返回最近被检查(inspected)的下一个对象。
$n(5) - 返回最近被检查的第n个对象。
inspect(object) - 将对象显示在 Inspector 中。
dir(object) - 返回一个对象的属性名数组。(译者注:跟 Python 学的?)
clear() - 清除控制台信息。
Posted by Nicholas Ding on 12th 八月 2006
前言
dojo是时下非常流行的javascript框架,它在自己的Wiki上给自己下了一个定义,dojo是一个用JavaScript编写的开源的DHTML工具箱。
dojo很想做一个“大一统”的工具箱,不仅仅是浏览器层面的,野心还是很大的。不过dojo带来了JavaScript编程的一些新想法,其中引入包机制进行动态加载是一个不错的概念。
理解dojo的包机制
其实dojo只需要一些很小的加载代码就可以用来加载它的各种包,它的官方站点上提供的dojo-ajax下载中包含的dojo.js体积还是比较庞大的,因为它将一些常用的包都包含在了js中, 但是很多时候我们并不需要这么多功能,还是按需加载比较好。
幸好在http://download.dojotoolkit.org/这个地址中我们还可以下载到dojo的各个自定义版本,其实包含的组件都是一样的,只不过dojo.js的大小有很大不同,那么,我们就从minimal版本下手。
下载之后会发现minimal版本包含的dojo.js只有18kb,里面仅仅包含了加载机制,非常不错。这样,我们就可以开始编写自己的dojo扩展。
dojo代码结构
解压缩后的目录里面包含src目录,src目录下存放有dojo的各个组件包,我们在这里面新建一个hello目录。
新建一个名为__package__.js文件,很类似Python的模块命名,这个__package__.js定义了在引入这个命名空间的时候默认导入多少类,以及这个命名空间的名字。
我们的目的是做一个dojo.hello.Echo扩展,那么在__package__.js中的代码应该这样:
// kwCompoundRequire 的作用是当你导入整个dojo.hello包的时候需要默认加载多少类
// 这些定义就在这个函数里面,common在这里表示默认的加载,这个参数不是固定的
// dojo希望自己是一个“大一统”的实现,所以考虑了非浏览器情况,可以有别的,譬如rhino
dojo.kwCompoundRequire({
common: [
"dojo.hello.Echo"
]
});
// 这个定义了包,默认这么写 | 原因嘛,当然是有的,看你的悟性了:-)
dojo.provide("dojo.hello.*");
我们指定了默认加载的类Echo,那么我们就去写Echo类,在hello目录中新建Echo.js,代码如下:
// 类名定义,JavaScript写的变扭,其实就是直接定义类名
dojo.provide("dojo.hello.Echo");
// 类定义部分,非常熟悉的代码
dojo.hello.Echo = function() {
this.name = "dojo.hello.Echo";
this.sayHello = function(greeting) {
return greeting;
}
}
扩展写好了,很简单,接下来就是掉用了,index.html如下。
<html>
<head>
<script language="javascript" src="dojo.js"></script>
<script language="javascript">
dojo.require("dojo.hello.*");
var echo = new dojo.hello.Echo();
document.write(echo.sayHello("Hello World"));
</script>
</head>
<body>
</body>
</html>
注意dojo.require("dojo.hello.*")回去请求两个文件,首先是__package__.js,这样一来就得到了之前在dojo.kwCompoundRequire里面指定的类列表,然后去加载Echo.js。你也可以直 接去加载Echo.js,只需要变成dojo.require("dojo.hello.Echo")
。
更多内容
这个例子非常简单的介绍了一下dojo的包加载机制,当然这个包中的类并没有引用其它类,dojo还允许在代码中动态加载其它类,当然了,这些都是通过XmlHttp来实现的,因为是同步模式,所以请求的类比较多并且都没有包含在dojo.js中的时候会有页面停顿的现象,这点还是需要注意的。
文中的代码下载:,dojo-hello.tar.gz
一些dojo的资源:
Posted in JavaScript, Ajax, Web应用 | No Comments »
Posted by Nicholas Ding on 17th 五月 2006
AJAX in Action
像其他人一样,当我看到一下RIA应用,例如Google Maps和Google Suggest的时候我都非常惊讶。我希望知道是如何实现的。现在,谜底揭开了,那就是AJAX。这是在我花了一段时间研究AJAX之后才知晓的。这里有一个很好的例子让我们知道AJAX是如何很好的应用在 JavaRSS.com 里面的。
什么是AJAX:
-
AJAX 是一个架构(architecture)并不是一种技术。AJAX代表异步的JavaScript和XML。
妙语(Punch Line):
-
延迟加载
问题:
-
当JavaRSS.com首页加载时,他同时加载了所有条目的介绍(如果你在设置中激活了)。这些介绍只有当你鼠标移动到该条目的上面的时候才显示。
现在的问题是用户不可能是鼠标移过所有的条目,所以预先加载所有的介绍不是个好主意。
解决方案: 使用AJAX,当鼠标移过的时候从服务器动态加载条目的介绍。
这么做可以使初始页的加载大小减小一半甚至更多,这样一来页面加载就更快,就内能得到一个更好的用户体验。
时序图:

我们首先会在onmouseover事件中调用JavaScript函数getDescription。下面是html代码:
<a href="/" οnmοuseοver="getDescription(3,1)">Java & J2EE News</a>
下面是 getDescription 函数的代码:
var url = 'http://localhost:8080/getDescription.jsp?channelId=' + channelId + '&itemId=' + itemId;
if (window.XMLHttpRequest) {
req = new XMLHttpRequest();
} else if (window.ActiveXObject) {
req = new ActiveXObject("Microsoft.XMLHTTP");
}
req.onreadystatechange = processRequest;
req.open("GET", url, true);
req.send(null);
XMLHttpRequest 对象将用来进行http连接并取回xml文档。我们需要检测一下是否是IE并且创建 XMLHttpRequest 对象。
if (window.XMLHttpRequest) {
req = new XMLHttpRequest();
} else if (window.ActiveXObject) {
req = new ActiveXObject("Microsoft.XMLHTTP");
}
设置回调函数,并且发送"GET"请求至服务器接收xml文档:
req.onreadystatechange = processRequest;
req.open("GET", url, true);
req.send(null);
JSP将根据适当的条目编号创建具有相应介绍的xml文档。
<%
String channelId = request.getParameter("channelId");
String itemId = request.getParameter("itemId");
//String description = new Channel(channelId).getItemDescription(itemId);
String description = "This is the description for the channelId: " + channelId + "and itemId: " + itemId;
if (description != null) {
response.setContentType("text/xml");
response.setHeader("Cache-Control", "no-cache");
response.getWriter().write("<description>" + description.toString() + "</description>");
} else {
//nothing to show
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
}
%>
检测HTTP请求返回状态码,状态为200,即OK。
function processRequest() {
if (req.readyState == 4) {
if (req.status == 200) {
parseMessages();
} else {
alert ( "Not able to retrieve description" );
}
}
}
readyState = 4 的情况下文档被加载。
readyState Status Codes:
- 0 = uninitialized
- 1 = loading
- 2 = loaded
- 3 = interactive
- 4 = complete
最后,我们解析XML文档并显示介绍。
问题: 唯一的问题就是我遭遇到的 "&" 字符。 "&" 在XML文档里面不是一个有效字符。所以我需要将他转换成 "&"。
function parseMessages() {
response = req.responseXML.documentElement;
itemDescription = response.getElementsByTagName('description')[0].firstChild.data;
alert(itemDescription);
}
下面是所有的代码:
HTML Code:
<a href="/" οnmοuseοver="getDescription(3,1)">Java & J2EE News<a>
JavaScript Code:
function getDescription(channelId,itemId) {
var url = 'http://localhost:8080/getDescription.jsp?channelId=' + channelId + '&itemId=' + itemId;
if (window.XMLHttpRequest) {
req = new XMLHttpRequest();
} else if (window.ActiveXObject) {
req = new ActiveXObject("Microsoft.XMLHTTP");
}
req.onreadystatechange = processRequest;
req.open("GET", url, true);
req.send(null);
}
function processRequest() {
if (req.readyState == 4) {
if (req.status == 200) {
parseMessages();
} else {
alert ( "Not able to retrieve description" );
}
}
}
function parseMessages() {
response = req.responseXML.documentElement;
itemDescription = response.getElementsByTagName('description')[0].firstChild.data;
alert ( itemDescription );
}
JSP Code:
<%
String channelId = request.getParameter("channelId");
String itemId = request.getParameter("itemId");
description = "This is the description for the channelId: " + channelId + "and itemId: " + itemId;
if (description != null) {
response.setContentType("text/xml");
response.setHeader("Cache-Control", "no-cache");
response.getWriter().write("<description>" + description.toString() + "</description>");
} else {
//nothing to show
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
}
%>
资源:
使用AJAX的Google站点:
关于作者:
Posted in Ajax | No Comments »
Posted by ShiningRay on 3rd 四月 2006
任何试过过Flickr、GMail、Google Suggest或者是Google Maps的人都会意识到一种新型的动态Web应用正在逐渐浮出水面。这些应用外观和表现都和传统的桌面应用程序很像,而他们不需要依赖于插件或者是特定于浏览器的功能。过去Web应用只是一系列HTML页面,他们任意一部份内容的更改都必须重新载入页面。像JavaScript编程语言和层叠样式表 (CSS)之类的技术已经成熟,可以有效地应用他们来创建高动态的Web应用,而且可以运行在所有的主流浏览器中。本文将会详细介绍你马上就可以使用的一些技术,让他们使你的Web应用像桌面应用更加丰富和更有交互性。
介绍异步JavaScript技术和XML(AJAX)
使用JavaScript技术,一个HTML页面可以异步地对服务器(一般是载入页面的服务器)发送请求并获取XML文档。然后JavaScript可以使用XML文档来更新或改动HTML页面的文档对象模型(DOM)。最近形成了一个术语AJAX(Asynchronous JavaScript Technology and XML)来描述这种交互模型。
AJAX其实不是很新的东西。这些技术对于Windows平台上专注于Internet Explorer的开发人员来说,已经存在好几年了。直到最近,这个技术才被作为Web远程技术或者远程脚本技术被大家了解。Web开发人员也有一段时间曾经使用过插件、Java applet和隐藏框架来模拟这种交互模型。最近发生的变化是,对XMLHttpRequest
对象的支持已经成为所有平台上的主流浏览器都包括的特性了。JavaScript技术的XMLHttpRequest
对象是。尽管在正式的JavaScript技术标准中并没有提到这种对象,然而今天主流的浏览器都对他提供了支持。而当代的浏览器如Firefox、Internet Explorer以及Safari在JavaScript技术和CSS的支持上有些细微的差别,但是这种差别是可以处理的。如果你要考虑支持较老的浏览器,AJAX也许就不能成为你的解决方法。
基于AJAX的客户端之所以独特的原因是客户端包含了用JavaScript嵌入的特定于页面的控制逻辑。应用JavaScript技术的页面基于事件进行交互,如文档载入、鼠标点击、焦点改变甚至是定时器。AJAX交互使得表现层逻辑更加清晰地与数据分离。一个HTML页面也可以根据需要每次读入适当的数据,而不是每次需要显示一个更改时都重新载入整个页面。AJAX要求一种不同的服务器架构来支持它这种交互模型。以前,服务器端Web应用关注于对每个导致服务器调用的客户端事件都生成HTML文档。然后客户端对每个回应都要重新读入并重新渲染完整的HTML页面。富Web应用(Rich Web Application)关注于,让一个客户端获取一个HTML文档让它表现为一个模板或者是一个容器,可以基于事件并使用从服务器端组件中获取的XML 数据来对文档注入内容。
一些AJAX交互的应用如:
- 实时表单数据检验:像用户ID、序列号、邮政编码或者是特殊的票据代码这类需要服务器端验证的数据也可以在用户提交表单之前进行验证。
- 自动补全:像电子邮件地址、姓名或城市名之类的表单数据都可以根据用户情况自动补全。
- 处理细节操作:根据一个客户端事件,一个HTML页面可以根据现存的一些数据再去获取更多详细的信息,如现在有一个产品列表,客户端可以控制查看单独的产品信息而无需刷新页面。
- 复杂的用户界面控件:像树型控件、菜单和进度条之类不要求页面刷新的控件也能实现。
- 页面内刷新数据:HTML页面可以从服务器上查询最新的数据如分数、股指、天气还有其它的特定于应用的数据。
- 服务器端通知:一个HTML页面可以通过对服务器进行定时查询来模拟一个服务器的事件通知推送,实现像通知客户端一个消息、刷新页面数据或将客户端重定向到另一个页面。
这个列表并未把所有的应用都列出来,但它已经显示了AJAX交互可以让Web应用比从前能做更多的事情。但尽管这些好处是值得关注的,这种方式也有一些缺点:
- 复杂度:服务器端开发人员必需理解,HTML客户端页面中的表现层逻辑以及生成HTML客户端页面所需的XML内容的服务器端逻辑。HTML页面开发人员必须了解JavaScript技术。如果开发新的框架和发展已有的框架来支持这种交互模型,那么AJAX应用的创建就会越来越简单。
XMLHttpRequest
对象的标准化:XMLHttpRequest
对象还不是JavaScript技术标准的一部分,这就意味着根据客户端的不同,应用的行为也有所会不同。 - JavaScript技术的实现:AJAX交互极大地依赖于JavaScript技术,而由于客户端的原因JavaScript还有一些细微的差别。见QuirksMode.org来了解更多关于浏览器之间区别的内容。
- 调试:AJAX应用也难于调试,因为流程逻辑是同时嵌在客户端中和服务器上的。
- 代码可见:客户端的JavaScript可以很容易通过“查看源代码”被人看见。一个没有良好设计的AJAX应用很可能被黑客攻击或被他人剽窃。
当开发人员在使用AJAX交互模型上获得更多的经验后,AJAX技术的框架和模式就会慢慢浮现出来。现在就关注于完全通用的AJAX交互框架,还为时过早。本文和相关的解决方案将关注于在现有的Java 2平台企业版(J2EE)上如何对AJAX进行支持,像servlet,JavaServer Page(JSP)软件、JavaServer Face应用和Java标准标签库(JSTL)。
AJAX交互剖析
现在我们已经讨论了AJAX是什么以及一些高层次的问题。那现在让我们把所有的零件放在一起来展示一个具有AJAX的J2EE应用。
首先考虑一个例子。一个Web应用包括了一个静态HTML页面,或者是一个由JSP生成的HTML页面,这个JSP中还包括了一个HTML表单,它需要服务器端逻辑来对表单中的数据进行检验,而不用刷新页面。一个名为ValidateServlet
服务器端组件(servlet)用来提供这种验证逻辑。图一描述了这种具有验证逻辑的AJAX交互的细节。
|
图1: 一个提供验证逻辑的AJAX交互
|
以下条目代表了图1中出来AJAX交互的过程:
- 发生一个客户端事件。
- 创建和配置一个
XMLHttpRequest
对象。 XMLHttpRequest
对象进行一个调用。 ValidateServlet
对请求进行处理。 ValidateServlet
返回一个包含了结果的XML文档。 XMLHttpRequest
对象调用callback()
函数并处理结果。 - 更新 HTML DOM。
现在让我们逐个研究这个AJAX模型的每一步。
1.发生一个客户端事件。
在一个事件发生时可以调用相应的JavaScript函数。在这里,validate()
函数可以被映射到一个链接或者是表单组件的onkeyup
事件上去。
<input type="text"
size="20"
id="userid"
name="id"
οnkeyup="validate();"> |
每次用户在表单域中按下一个键时,表单元素将都调用validate()
函数。
创建和配置一个XMLHttpRequest
对象
var req;
function validate() {
var idField = document.getElementById("idField");
var url = "validate?id=" + escape(idField.value);
if (window.XMLHttpRequest) {
req = new XMLHttpRequest();
} else if (window.ActiveXObject) {
req = new ActiveXObject("Microsoft.XMLHTTP");
}
req.open("GET", url, true);
req.onreadystatechange = callback;
req.send(null);
} |
validate()
函数建立了一个XMLHttpRequest
对象并对象中的open函数。open函数需要两个参数:HTTP方法,可以是GET
或POST
; 和对象进行交互的服务器端组件的URL;一个布尔变量,表示是否要进行异步调用。API是XMLHttpRequest.open(String method, String URL, boolean asynchronous)
。如果一个交互被设置为异步, (true
) 那就必须指明一个回调函数。可以使用req.onreadystatechange = callback;
来设置这个交互的回调函数。详细内容见第六节。
3.XMLHttpRequest
对象进行调用
当收到了语句req.send(null);
,就会进行一次调用。HTTPGET
的情况下,内容可以是null
或者留空。当调用XMLHttpRequest
的这个函数时,也会对已经配置了的URL进行调用。在下面这个例子中,要发送的数据(id
)将作为一个URL参数。
使用HTTPGET
,两个重复的请求将返回同样的结果。当使用HTTPGET
方法时,要注意URL的长度,包括已经转义的URL参数,可能会受到某些浏览器和服务器端的Web容器的限制。当发送的数据会影响到服务器端的应用程序的状态时,就应该使用HTTPPOST
方法。使用HTTPPOST
必须要对XMLHttpRequest
对象设置一个Content-Type
头,使用以下语句:
req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
req.send("id=" + escape(idTextField.value)); |
当从JavaScript中发送表单值得时候,你应该考虑对字段值进行编码。JavaScript中有一个函数escape()
,应该用他来确保区域化的内容被正确编码,同时特殊字符也被正确转义。
4. ValidateServlet
对请求进行处理.
一个映射到URI "validate" 的servlet将检验user ID是不是已经在数据库中存在了。
一个servlet处理一个XMLHttpRequest ,就像对待其它的HTTP请求一样。
下面的例子显示了服务器从请求中抽取出id
参数并检验是否被占用了。
public class ValidateServlet extends HttpServlet {
private ServletContext context;
private HashMap users = new HashMap();
public void init(ServletConfig config) throws ServletException {
this.context = config.getServletContext();
users.put("greg","account data");
users.put("duke","account data");
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
String targetId = request.getParameter("id");
if ((targetId != null) && !users.containsKey(targetId.trim())) {
response.setContentType("text/xml");
response.setHeader("Cache-Control", "no-cache");
response.getWriter().write("<message>valid</message>");
} else {
response.setContentType("text/xml");
response.setHeader("Cache-Control", "no-cache");
response.getWriter().write("<message>invalid</message>");
}
}
} |
在这个例子中,一个简单的HashMap用来存放存在的用户名。在这个例子中,我们假设用户的ID是duke
。
5.ValidateServlet
返回一个包含结果的XML文档
用户ID "duke" 在users HashMap
的用户ID列表中出现了。将在应答中写一个包含值为invalid
的message
元素的XML文档。更复杂的用例将要求DOM、XSLT或其他API来生成这个应答。
response.setContentType("text/xml");
response.setHeader("Cache-Control", "no-cache");
response.getWriter().write("<message>invalid</message>"); |
开发人员必须注意两个事情。第一,Content-Type
必须设为text/xml
。第二,Cache-Control
必须设为no-cache
。XMLHttpRequest
对象只会处理Content-Type
为text/xml
的应答,同时把将Cache-Control
设为no-cache
将确保浏览器不会从缓存相同的URL(包括参数)返回的应答。
6.XMLHttpRequest
对象调用callback()
函数并处理结果。
XMLHttpRequest
对象已经配置为当有readyState
改变的时候就调用callback()
函数。让我们假设已经ValidateServlet
调用了而且ValidateServlet
是4
,表示XMLHttpRequest
的调用已经完成。HTTP状态代码200
表示一个成功的HTTP交互。
function callback() {
if (req.readyState == 4) {
if (req.status == 200) {
// update the HTML DOM based on whether or not message is valid
}
}
} |
浏览器维护了一个所显示的文档的对象形式(也就是所谓的Docuemt Object Model或DOM)。HTML页面中的JavaScript可以访问DOM,同时在页面载入完之后,可以使用API来修改DOM。
根据成功的请求,JavaScript代码可以修改HTML页面的DOM。从ValidateServlet
获得的对象形式的XML文档可以通过req.responseXML
在JavaScript中获得,req
是一个XMLHttpRequest
对象。DOM API给JavaScript提供了获取这个文档中的内容以及修改HTML页面的DOM的方法。所返回的字符串形式的XML文档可以通过req.responseText
获得。现在我们看看如何在JavaScript中使用DOM API,先看以下从ValidateServlet
返回的XML文档。
<message>
valid
</message> |
这个例子是一个简单的只包含了一个message
元素的XML片断,里面只有一个简单的字符串valid
或invalid
。一个更高级的例子可以包含多于一个的消息和可以给用户看的有效的名字:
function parseMessage() {
var message = req.responseXML.getElementsByTagName("message")[0];
setMessage(message.childNodes[0].nodeValue);
} |
parseMessages()
函数将处理一个从ValidateServlet
获取的XML文档。这个函数会调用setMessage()
with the,并给出message
作为参数来更新HTML DOM。
7.更新HTML DOM
JavaScript技术可以使用很多API从HTML DOM中获得任何元素对象的引用。推荐的获得元素引用的方法是调用document.getElementById("userIdMessage")
, "userIdMessage"
是HTML文档中出现的一个元素的ID属性。有了这个元素的引用,就可以使用JavaScript来修改元素的属性、修改元素的样式、添加、删除或修改子元素。
一个常见的改变元素主体内容的方法是设置元素的innerHTML
属性,如下所示:
<script type="text/javascript">
function setMessage(message) {
var userMessageElement = document.getElementById("userIdMessage");
userMessageElement.innerHTML = "<font color=/"red/">" + message + " </font>";
}
</script>
<body>
<div id="userIdMessage"></div>
</body> |
受到影响的那部分HTML页面会立刻根据innerHTML
的设置重新渲染。如果innerHTML
属性包含类似<image>
或者是<iframe>
之类的元素,那么由那些元素所指定的内容同样会被获取并渲染。
这种途径的主要缺点是HTML元素是作为字符串硬编码在JavaScript中的。JavaScript中硬编码的HTML标记不是一种好的实践,因为它使代码难于阅读、维护和修改。我们应该考虑在JavaScript中使用DOM API来创建和修改HTML元素。把显示和JavaScript代码的字符串混在一起只会让页面更难于阅读和编辑。
另一种修改HTML DOM的方法是动态地产生新的元素并把他们作为子元素追加到目标元素,如下面的例子所示:
<script type="text/javascript">
function setMessage(message) {
var userMessageElement = document.getElementById("userIdMessage");
var userIdMessageFont = document.getElementById("userIdMessageFont");
var messageElement = document.createTextNode(message);
if (userMessageElement.childNodes[0]) {
// 更新元素
userIdMessageFont.replaceChild(messageElement, userIdMessageFont.childNodes[0]);
} else {
// 建立一个新的元素
var fontElement = document.createTextNode("font");
fontElement.setAtribute("id", "userIdMessageFont");
fontElement.setAtribute("color", "red");
userMessageElement.appendChild(fontElement);
fontElement.appendChild(messageElement);
}
}
</script>
<body>
<div id="userIdMessage"></div>
</body> |
这个范例展示了JavaScript技术的DOM API可以用来更有目的地建立或改变一个元素。当然JavaScript的DOM AP在不同的浏览器上也可能有差别,所以你必须在开发应用程序时小心。
Java BluePrint的解决方案目录
TheJava Blueprints Solutions Catalog是用来收集J2EE技术上AJAX的最佳实践的。每个解决方案包含一个问题和方法的描述、一个设计文档和可运行的源码。这些解决方案是为了让你根据需要在自己的应用程序中复用。以下是已经提供的AJAX交互:
自动补全
自动补全提供了当用户在一个HTML表单中输入一个请求时对数据浏览的简化方式。当用户面对一大片数据时,可以在输入数据时把可能的完整形式显示给用户。然后选择其中一个完整形式可以保证用户输入的数据已经存在在服务器上。
考虑一个大公司的一个名字查找的Web应用。如图2所示,只要输入姓或名的开头几个字母就可以得到人的列表。用户可以然后就只要点击一下就可以浏览用户的详细信息。
|
图2:名字自动补全
|
进度条
在Web应用中,一个服务器端任务也可能要花一段时间去完成。这段时间很可能会超过HTTP交互的时间上限(超时)。当用户不知道这个任务什么时候才能完成时,用户很可能会重新提交一次表单或直接退出会话状态。一般来说,Web应用使用页面刷新来跟踪服务器端操作的状态,这种方式可能会让人厌烦而且也不准确。AJAX可以用来仅在一个HTML页面中跟踪服务器端操作的状态而无需刷新页面。用户可以以图形方式看到服务器端操作的进度,如图3。
 |
图3:进度条
|
刷新数据
向一个HTML页面提供最新的数据或服务器消息提醒在现在的Web世界中也是十分重要的,因为现在的Web世界中数据一直不停变化。尽管它不是一个实实在在的推送技术,但它可以通过使用AJAX交互不断进行查询来模拟。当数据需要更新或者要进行提醒,HTML页面将会动态地改变。图4显示了HTML页面中的一个服务器端计数器。这个计数器会在页面后台自动更新。
 |
图4:服务器端计数器在刷新数据
|
实时检验
不是所有的表单域都可以单独用JavaScript技术在客户端完成。某些表单数据要求服务器端的验证逻辑。传统和Web应用曾使用页面刷新来完成这种验证,但这可能有些让人烦。
考虑一个需要一个唯一用户ID的Web应用。使用AJAX交互,用户可以在输入的时候就知道ID是否有效(图5)。
 |
图5:指出用户ID无效
|
当一个用户输入了一个无效的用户ID,应用程序禁止了提交按钮并且向用户显示了一个信息(图6)。
 |
图6:用户ID通过验证
|
用户马上就能知道用户ID是可用的也是有效的。
最后的思考
我们已经看到AJAX交互可以解决很多问题。配合HTTP处理、数据库、Web服务、XML处理和业务对象等API,J2EE技术已经提供了一个开发和部属基于AJAX应用的一个良好的基础。有了对于这个交互模型的更好的理解,今天的应用程序可以变得更加有交互性,给最终用户更好的体验。
使用AJAX要求你使用支持XMLHttpRequest
对象的最新浏览器版本。使用AJAX还要求大量对JavaScript技术和CSS的应用。作为一个应用程序架构师或是一个开发人员,你要会针对浏览器支持、架构复杂度和对开发人员的培训等方面来衡量开发一个富应用的需要。当AJAX编程模型不断地发展,现有的技术和框架会让这种转变更加容易。
很明显的是,突出的Web应用都越来越有交互性了。那么你的呢?
更多信息
Greg Murray 是is a Sun Microsystems 的一名工程师,是servlet标准的领导人,BluePrint小组的前成员,在这个小组时他已经开始关注Web层次问题。他也是《Enterprise Applications With the Java 2 Platform,Enterprise Edition和Designing Web Services With the J2EE 1.4 Platform(Addison-Wesley)》一书的协助编撰者。