一套通用的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&param2=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>

    下面是java中生成xml的方法:

        PrintWriter out = response.getWriter();
        StringBuffer buffer = new StringBuffer();
        out.println("<?xml version=\"1.0\" encoding=\"gbk\"?>");
        for (int i = 0; i < 10; i++) {
            buffer.append("\n\t<children>");
            buffer.append("\n\t\t<id>").append(1)
                   .append("</id>");
            buffer.append("\n\t\t<name>").append(2)
                   .append("</name>");
            buffer.append("\n\t</children>");
        }
        out.println(buffer.toString());

 

發佈了35 篇原創文章 · 獲贊 0 · 訪問量 4302
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章