如今web应用上,ajax技术是大行其道。
ajax框架层出不穷,prototype,dojo,jquery,mootools,dwr,buffalo,ext,yui,spry。。。
ajax框架的出现,在提升开发生产效率的同时,也让不少同学不明其内在原理,仅仅成为了某些框架的使用者。
(对于产品生产是好事,对于技术追求是坏事)
本文不涉及任何ajax框架的使用,本文仅通过一个模拟需求,在不使用任何ajax框架的前提下,以demo演示的方式,
向大家介绍ajax的原理以及应用场景。
ajax全称是:
Asynchronous JavaScript And XML。
其本意是,通过javascript技术(JavaScript),通过异步http请求方式(Asynchronous),得到XML文本内容(XML)之后,通过javascript技术局部刷新web页面内容。
从广义的概念看,只要符合“异步请求,局部刷新web页面”的技术,都可以成为ajax。
未必一定要使用javascript,一般情况下,大多数client端脚本代码都可以;返回内容也未必一定要是xml,目前json格式,更为流行。
如何异步请求内容呢?
以javascript代码作演示,如下:
function xmlhttpPost(url,func) {
var xmlHttpReq = false;
var self = this;
// Mozilla/Safari
if (window.XMLHttpRequest) {
self.xmlHttpReq = new XMLHttpRequest();
}
// IE
else if (window.ActiveXObject) {
self.xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
}
self.xmlHttpReq.open('POST', url, true);
self.xmlHttpReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
self.xmlHttpReq.onreadystatechange = function() {
if (self.xmlHttpReq.readyState == 4) {
func(self.xmlHttpReq.responseText);
}
}
self.xmlHttpReq.send(null);
}
参数一,url:表明异步请求的资源地址
参数二,func:表明请求结束后,采用什么函数对请求结果内容进行回调处理
其实,这一个js代码,就诠释了ajax的全部含义--异步请求资源,将得到的资源内容,使用指定的function进行处理。
所以,ajax很简单,大家千万别被如今层出不穷的ajax框架给吓怕了。要了解ajax的原理,就只要参看这段代码即可。
如今的一些框架,仅仅在此基础上,是封装了一些公用的函数,方便开发人员调用。(当然,说说简单,其实所谓的这些函数,大大方便了开发人员使用ajax技术。具体请参看ajax framework的官方介绍。)
特别说明:这个xmlhttpost方法改进了
simple-ajax。在原基础上,将回调方法作为参数传递。
解释了原理性的内容之后,接下来,以一个模拟的应用场景,demo说明ajax的使用,以及它的主要应用场景。
模拟场景:
目录选择,即当选择一个目录的时候,需要显示这个目录下的所有子目录。
首先,我们来虚拟一个目录结构,如下:
那么,要实现目录选择,有三个方式:
1)页面初始化的时候,服务端将所有的目录信息都put到页面中。
优点:选择操作简单,有了全部的目录信息,做选择操作,都可以使用js完成,无需和服务端进行交互
缺点:当目录信息很大的时候,比如有上万个节点,整个目录信息有1m左右大小,那么要渲染这个页面,估计得20秒左右(视网速)
并且,很可能用户仅仅只要选择有限的几个节点就可以,比如上万个节点中选择6-7个节点,那么浪费太大了;
2)页面初始化的时候,服务端将当前需要的节点信息put到页面上,一旦有选择操作,重新刷新页面。
优点:选择操作简单,对于节点信息,每次取需要的内容,不存在浪费现象
缺点:每次都要刷新整个页面,除节点信息外,其他不变的东西都需要重新从服务端取,增加无谓的消耗。
3)页面初始化的时候,服务端将当前需要的节点信息put到页面上,一旦有选择操作,只刷新节点相关的内容;
优点:每次只load需要的信息,局部刷新页面内容,不存在任何浪费现象
缺点:需要异步请求数据,每次请求都需要和服务器交互,选择操作稍显复杂(异步请求,局部刷新)
通过这三种方式做对比,发现ajax主要适用的场景如下:
1)整体内容量大(几百k,几m,甚至几十m),而页面只需要其中一小部分信息即可;
2)数据显示,只涉及一个页面中部分数据信息的变动;
特别说明:至于使用ajax性能如何,需要对1,3两个情况做性能测试,权衡使用。
针对第三种方案,
首先需要一个取节点资源的url,
演示代码中,为了演示方便,使用php语言,而非使用主要语言java;
tree_node.php
<?php
$id = $_GET['id'];
if("1" == $id) {
echo("{\"id\":1,\"parentId\":-1,\"name\":\"1-1\",\"children\":[{\"id\":2,\"name\":\"2-1\"},{\"id\":3,\"name\":\"2-2\"},{\"id\":4,\"name\":\"2-3\"}]}");
} else if("2" == $id) {
echo("{\"id\":2,\"parentId\":1,\"name\":\"2-1\",\"children\":[]}");
} else if("3" == $id) {
echo("{\"id\":3,\"parentId\":1,\"name\":\"2-2\",\"children\":[]}");
} else if("4" == $id) {
echo("{\"id\":4,\"parentId\":1,\"name\":\"2-3\",\"children\":[{\"id\":5,\"name\":\"3-1\"},{\"id\":6,\"name\":\"3-2\"}]}");
} else if("5" == $id) {
echo("{\"id\":5,\"parentId\":4,\"name\":\"3-1\",\"children\":[]}");
} else if("6" == $id) {
echo("{\"id\":6,\"parentId\":4,\"name\":\"3-2\",\"children\":[{\"id\":7,\"name\":\"4-1\"}]}");
} else if("7" == $id) {
echo("{\"id\":7,\"parentId\":6,\"name\":\"4-1\",\"children\":[]}");
} else {
echo("");
}
?>
该文件中,写死了目录结构(一般情况下,往往根据树对象,动态取得需要的节点)。
通过js,动态请求节点信息,部分刷新页面内容:
<script type="text/javascript">
//模拟需求js
var nodeSelect = function(text) {
var tree = toJsonObje(text);
var options = document.getElementById("tree").options;
options.length = 0;
options.add(new Option("请选择","-1"));
if(tree == null) {
return;
} else {
var children = tree.children;
for(i = 0; i < children.length; i++) {
var child = children[i];
options.add(new Option(child.name,child.id));
}
if(tree.parentId != "-1") {
options.add(new Option("上一级",tree.parentId));
}
}
document.getElementById("l").innerHTML = "当前位置:" + tree.name;
}
function nodeSelectAjax(id) {
var TREE_NODE_URL = "tree_node.php";
var url = TREE_NODE_URL + "?id=" + id;
xmlhttpPost(url,nodeSelect);
}
</script>
nodeSelectAjax,异步请求节点资源
nodeSelect,回调函数,根据请求信息,局部刷新页面
至于请求资源信息格式,任何方式都可以,只要client端能解析就行。
目前json格式,比较流行。
最后,附上java使用json库,生成json格式的方法:
JSONObject node = new JSONObject();
node.put("id", 1);
node.put("parentId", -1);
node.put("name", "1-1");
JSONArray children = new JSONArray();
JSONObject c1 = new JSONObject();
c1.put("id", 2);
c1.put("name", "2-1");
JSONObject c2 = new JSONObject();
c2.put("id", 3);
c2.put("name", "2-2");
children.put(c1);
children.put(c2);
node.put("children", children);
System.out.println(node.toString());
ajax demo
工程文件编码:utf-8
工程运行:http server with php supported
ubuntu firefox下测试通过
其他:
不知道是不是ie的bug,居然不支持 select.innerHTML = value的方式
只能通过select.options.add(new Option("content","value") 动态往select中添加选项。