一套通用Ajax架構

來源:互聯網
上載者:User
最近由於項目需要,專心研究了一下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&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>

七、總結
我認為Ajax的應用最好根據自己的需求,來實現相應的功能,盡量避免JavaScript代碼過多,拖累用戶端瀏覽器。
由於JavaScript代碼設計過於靈活,如果JavaScript程式員水平相當,肯定能夠開發出很好的JavaScript程式,如果
JavaScript程式員水平良莠不齊,最好避免多人同時開發一套JavaScript程式,防止JavaScript代碼品質降低。由於JavaScript調試起來非常不方便,建議大家多多使用FireFox瀏覽器的錯誤控制台,會給大家提供很多的方便。
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.