您的位置:首页 > 其它

一套通用Ajax框架 .

2013-09-09 17:27 411 查看
最近由于项目需要,专心研究了一下Ajax的相关程序设计,本来一开始想用Prototype或者jQuery等框架,后来发现其实用不到这些框架里面的那么多内容,强行使用的话只能拖累我网站的访问者,降低用户体验,因此决定自己写一套适合自己需求的Ajax代码库。

在这套Ajax代码库中,实现了如下的功能:
1、Ajax远程调用数据
2、通过Ajax异步提交Form表单
3、返回数据后,能够将数据绑定到页面的相关控件内(如:div、select、ul、span等等)
4、让Ajax程序支持浏览器的前进、后退按钮

一、什么是Ajax,他都能做什么?

AJAX全称为“Asynchronous JavaScript and XML”(非同步JavaScript和XML),是一种创建互动式网页应用的网页开发技术。
使用Ajax的最大优点,就是能在不更新整个页面的前提下维护数据。这使得Web应用程序更为迅捷地回应用户动作,并避免了在网络上发送那些没有改变过的信息。
Ajax不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。就像DHTML应用程序那样,Ajax应用程序必须在众多不同的浏览器和平台上经过严格的测试。随着Ajax的成熟,一些简化Ajax使用方法的程序库也相继问世。同样,也出现了另一种辅助程序设计的技术,为那些不支持JavaScript的用户提供替代功能。

二、核心代码

所谓核心代码就是提供一个能够跨浏览器的Ajax调用代码,这部分代码是后面扩展代码的必备部分,在这部分代码中我们提供了一个创建XMLHttpRequest对象并能够与Web服务器进行异步数据交换。

在我写的这些代码中,自定义了两个相关的函数,一个是通用的获取HTML对象函数,还有一个就是自动过滤字符串开头结尾的空格,代码如下:

function $( elementId ) {

return document.getElementById(elementId);

}

function trim(str){ //删除左右两端的空格

return str.replace(/(^/s*)|(/s*$)/g, "");

}

Ajax的核心代码如下:

/*

* 根据不同的浏览器,获取Ajax对象

*/

function getAjaxObject() {

var xmlHttpRequest;

// 判断是否把XMLHttpRequest实现为一个本地javascript对象

if(window.XMLHttpRequest){

xmlHttpRequest = new XMLHttpRequest();

}else if(window.ActiveXObject){ // 判断是否支持ActiveX控件

try{

// 通过实例化ActiveXObject的一个新实例来创建XMLHttpRequest对象

xmlHttpRequest = new ActiveXObject("Microsoft.XMLHTTP"); // msxml3以上版本

}catch(e){

try{

// 通过实例化ActiveXObject的一个新实例来创建XMLHttpRequest对象

xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP"); // msxml3以下版本

}catch(e){}

}

}

if ( !xmlHttpRequest ) {

alert("创建Ajax对象失败,您将无法正常浏览网页");

}

return xmlHttpRequest;

}

/*

* 异步方式提交请求

*/

function sendRequestByAjax(method, url, data, dataHandler) {

// 获取Ajax对象

request = getAjaxObject();

// 设置回调函数

if( !IE4 ){

request.onload = dataHandler;

} else {

request.onreadystatechange = dataHandler;

}

request.open(method, url, true); // true代表使用异步方式 false代表使用同步方式

// 处理提交方式

if ( "get" == method.toLowerCase() ) {

// 使用GET方式提交数据

var urls = url.split("?");

if ( urls[1] ==
"" || typeof(urls[1]) == "undefined" ) {

url = urls[0] + "?" + data;

} else {

url = urls[0] + "?" + urls[1] +
"&" + data;

}

data = null; // for GET method,request必须为空

} else if (
"post" == method.toLowerCase() ){

// 使用POST方式提交数据

request.setRequestHeader("Content-Type","application/x-www-form-urlencoded");

}

request.send(data);

}

三、回调函数以及数据解析

根据Ajax提出者Jesse James Garrett建议,Ajax使用XHTML+CSS来表示信息,使用JavaScript操作DOM(Document Object Model)进行动态显示及交互,使用XML和XSLT进行数据交换及相关操作,由于Opera浏览器不支持XSLT格式对象,也不支持XSLT,所以现在一般情况下都是使用XML进行数据传递。

在回调函数中,会出现request的一些相关属性,其代表值如下:
readyState:提供当前 HTML 的就绪状态。

0:请求未初始化

1:请求已经建立,但是还没有发送(还没有调用 send())

2:请求已发送,正在处理中(通常现在可以从响应中获取内容头)

3:请求在处理中,通常响应中已有部分数据可用了

4:响应已完成

status:提供当前HTML的状态码

401:未经授权

403:禁止访问

404:没找到访问页

200:正常

回调函数如下所示:

/*

* 返回数据格式为XML的回调函数

*/

function xmlCallBack() {

// 数据接收完成

if( request.readyState == 4 ){

// 数据正常接收

if( request.status == 200 ){

// 调用XML文件解析函数

parseXMLMessage();

} else {

// 显示错误信息

alert("Not able to retrieve description"+request.statusText);

}

}

}

/*

* XML文件解析函数

*/

function parseXMLMessage() {

// 获取返回的XML文件

var xmlDoc=request.responseXML.documentElement;

// 解析XML文件

parseXML("elementId", xmlDoc);

}

/*

* 解析XML文件

* @param elementId 要将数据绑定的对象Id

* @param xmlDoc 要解析的XML文件

*/

function parseXML(elementId, xmlDoc) {
// 这里XML文件的格式根据你的自定义,自行修改

var xmlRoot = xmlDoc.getElementsByTagName("items");

var dataType = xmlRoot[0].getAttribute("dataType");

var items = xmlDoc.getElementsByTagName('item');

switch ( dataType.toLowerCase() ) {

case "array" :

// 返回对象为结果集

bindItems(elementId, items);

break;

case "string" :

// 返回对象为字符串

bindText(elementId, items[0].childNodes[0].firstChild.nodeValue);

}

}

如果Ajax调用后返回的是一个HTML页面,则可以使用下面的这个回调函数:

/*

* HTML文件解析函数

*/

function htmlCallBack() {

if( request.readyState == 4 ){

if( request.status == 200 ){

parseHTMLMessage();

} else {

alert("Not able to retrieve description"+request.statusText);

}

}

}

/*

* 解析HTML文件

*/

function parseHTMLMessage() {

// 获取返回的HTML代码

var htmlCode = request.responseText;

// 绑定HTML代码

bindText("elementId", htmlCode);

}

四、数据绑定

数据绑定根据不同的控件类型,可以使用以下两个数据绑定函数,能够实现绑定select控件、ul无序列表、插入HTML代码等:

/*

* 绑定结果集

*/

function bindItems(elementId, items) {

var elem = $(elementId);

// 判断要绑定的对象,类型是否匹配

if ( elem.tagName.toLowerCase() !=
"select" && elem.tagName.toLowerCase() != "ul" ) {

alert("数据类型不匹配,无法进行数据绑定");

return;

}

// 绑定select

if ( elem.tagName.toLowerCase() ==
"select" ) {

while ( elem.childNodes.length > 0 ) {

// 清除现有数据

elem.removeChild(elem.childNodes[0]);

}

// 绑定数据

for ( var i = 0; i < items.length; i++ ) {

var option = document.createElement("OPTION");

var Data = items[i];

option.value = Data.childNodes[0].firstChild.nodeValue;

option.text = Data.childNodes[1].firstChild.nodeValue;

elem.options.add(option);

}

} else if ( elem.tagName.toLowerCase() ==
"ul" ) {

// 绑定ul列表

elem.innerHTML = "";

// bind data

for ( var i = 0; i < items.length; i++ ) {

var Data = items[i];

var urlAddress = Data.childNodes[0].firstChild.nodeValue;

var showText = Data.childNodes[1].firstChild.nodeValue;

var innerCode =
"<li><a href=/"" + urlAddress + "/" title=/"" + showText +
"/">" + showText +
"</a></li>";

elem.innerHTML += innerCode;

}

}

}

/*

* 绑定字符串,也可以实现绑定HTML代码

*/

function bindText(elementId, value) {

var elem = $(elementId);

// 分析绑定对象类型

switch ( elem.tagName.toLowerCase() ) {

case "div":

case "span":

case "textarea":

elem.innerHTML = value;

break;

case "input":

elem.value = value;

break;

default:

alert("数据类型不匹配,无法进行数据绑定");

return;

}

saveHistory(elementId); // 保存历史记录用于实现浏览器的前进、后退按钮

}

五、进阶功能——实现Ajax提交Form表单

通过Ajax提交Form有以下两个非常重要的地方:
1、需要解析所有Form中的控件,将控件拼成类似于“?param1=value1¶m2=value2......”这样的字符串,然后通过“POST”模式异步提交,将上面拼成的字符串通过request.send(data)发送到服务器。
2、关于文件上传,由于我没有这方面的需求,没有写出一个测试后的代码,但通过查阅相关资料,看到可以通过隐藏IFrame来实现这一功能。

通过Ajax异步提交表单的代码如下:

/*

* 通过Ajax异步提交表单

*/

function submitFormByAjax(formId) {

sendRequestByAjax($(formId).method, $(formId).getAttributeNode("action").value, encodeFormData($(formId)), htmlCallBack);

}

解析Form内控件,并拼成字符串的函数如下:

/*

* 分析Form表单数据

* @param formElement Form对象

*/

function encodeFormData(formElement) {

var whereClause = "";

var and = "";

for ( i = 0 ; i < formElement.length ; i++ ) {

var element = formElement[i];

if ( element.name != "" ) {

if (element.type=='select-one') {

element_value = element.options[element.selectedIndex].value;

} else if ( element.type == 'checkbox' || element.type == 'radio' ) {

if ( element.checked ==
false ) {

break;

}

element_value = trim(element.value);

} else {

element_value = trim(element.value);

}

whereClause += and + trim(element.name) + '=' + element_value.replace(//&/g,"%26");

and = "&"

}

}

return whereClause;

}

六、进阶功能——实现浏览器的前进、后退按钮

很多人在使用了Ajax技术后会发现,浏览器的前进、后退按钮无效了,大大降低了用户体验,曾经这一点也被作为Ajax技术的弊端而大范围讨论,后来经过不断的尝试,终于实现了这一功能,听起来很简答,就是通过一个隐藏的IFrame,使用JavaScript改变 IFrame的src属性而激活浏览器的前进、后退按钮。再通过一个特殊的JavaScript函数,实现更新页面数据。

具体的代码如下:

var historyValue =
new Array(10); // 保存记录的最大次数

var historyCount = 0;

/*

* 保存历史记录

* @param elementId 要保存的区域ID

*/

function saveHistory(elementId) {

// "historyFrame"隐藏的IFrame的ID属性值

var iframeDocument = $("historyFrame");

if ( iframeDocument !=
null ) {

if ( historyCount == 9 ) {

historyCount = 0;

} else {

historyCount++;

}

historyValue[historyCount] = new Array(2);

historyValue[historyCount][0] = elementId;

var element = $(elementId);

historyValue[historyCount][1] = element.innerHTML;

iframeDocument.src = "/history.jsp?" + historyCount;

}

}

/*

* 获取历史记录

* @param historyIndex 历史记录索引号

*/

function getHistory(historyIndex) {

if ( historyIndex != historyCount ) {

if ( historyValue[historyIndex] ) {

historyCount = historyIndex;

}

var element = $(historyValue[historyCount][0]);

element.innerHTML = historyValue[historyCount][1];

}

}

history.jsp页面中的代码很简单,只有以下代码:

<script>

var url=window.location.href;

if(url.indexOf('?')>-1)

{

parent.getHistory(url.substr(url.indexOf('?')+1));

document.write(window.location.search.substr(1));

}

</script>

在页面最下端记得写上下面的代码:

<iframe
id="historyFrame"
name="historyFrame"
src="/history.jsp?0"
height="0px"
frameborder="no"></iframe>

七、总结

我认为Ajax的应用最好根据自己的需求,来实现相应的功能,尽量避免JavaScript代码过多,拖累客户端浏览器。由于JavaScript代码设计过于灵活,如果JavaScript程序员水平相当,肯定能够开发出很好的JavaScript程序,如果 JavaScript程序员水平良莠不齐,最好避免多人同时开发一套JavaScript程序,防止JavaScript代码质量降低。
由于JavaScript调试起来非常不方便,建议大家多多使用FireFox浏览器的错误控制台,会给大家提供很多的方便
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: