[原創]ExtAspNet秘密花園(十) — Ajax特性


為了深入理解ExtAspNet的Ajax特性,我們還是先來看看Asp.Net中的回發機制,繼而講解ExtAspNet是如何對此回發過程進行改造,來實現ExtAspNet所特有的原色Ajax。

 

Asp.Net的回發機制

簡單說來,Asp.Net的回發過程是這樣:首先服務器將服務器端控件渲染為HTML返回給瀏覽器,當用戶進行某項操作時,通過表單提交的方式將控件相關數據提交到服務器,然后在服務器端恢復控件狀態並觸發相應事件。

 

在Asp.Net中有兩種表單的提交方式:

1. 通過type="submit"的默認表單提交

下面來看一個簡單的示例:

ASPX頁面:

   1:  <form id="form1" runat="server">
   2:      <asp:Button ID="Button1" runat="server" Text="Button1"  OnClick="Button1_Click">
   3:      </asp:Button>
   4:  </form>
生成的HTML標簽為:
   1:  <html>
   2:      
   3:      <head>
   4:          <title></title>
   5:      </head>
   6:      
   7:      <body>
   8:          <form name="form1" method="post" action="textbox.aspx" id="form1">
   9:              <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMjA0…6y+e3Tou1Yo="
  10:              />
  11:              <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="/wEWAgL…PagKn2HgW"
  12:              />
  13:              <input type="submit" name="Button1" value="Button1" id="Button1" />
  14:          </form>
  15:      </body>
  16:   
  17:  </html>

 

點擊Button1提交表單時,HTTP請求參數如下所示:

image

 

回顧整個過程,表單提交是通過點擊提交按鈕(type=submit)觸發的,在HTTP請求參數中我們發現Button1=Button1,這個參數是瀏覽器的默認添加的。服務器端也正是根據這個參數來找到點擊了那個控件,並觸發相應的服務器端事件的。

 

2. 通過JavaScript控制的表單提交

我們對上面的示例稍作修改:

ASPX頁面:

   1:  <form id="form1" runat="server">
   2:      <asp:Button ID="Button1" runat="server" Text="Button1"  UseSubmitBehavior="false" OnClick="Button1_Click">
   3:      </asp:Button>
   4:  </form>

 

生成的HTML標簽為:

   1:  <html>
   2:  <head><title></title></head>
   3:   
   4:  <body>
   5:      <form name="form1" method="post" action="textbox.aspx" id="form1">
   6:   
   7:      <input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
   8:      <input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
   9:      <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMjA0…e3Tou1Yo=" />
  10:   
  11:  <script type="text/javascript">
  12:  //<![CDATA[
  13:  var theForm = document.forms['form1'];
  14:  if (!theForm) {
  15:      theForm = document.form1;
  16:  }
  17:  function __doPostBack(eventTarget, eventArgument) {
  18:      if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
  19:          theForm.__EVENTTARGET.value = eventTarget;
  20:          theForm.__EVENTARGUMENT.value = eventArgument;
  21:          theForm.submit();
  22:      }
  23:  }
  24:  //]]>
  25:  </script>
  26:   
  27:      <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="/wEWAgLlxsf1…wCPagKn2HgW" />
  28:   
  29:      <input type="button" name="Button1" value="Button1" onclick="javascript:__doPostBack('Button1','')" id="Button1" />
  30:      </form>
  31:  </body>
  32:  </html>

 

點擊Button1提交表單時,HTTP請求參數如下所示:

image

 

雖然兩次得到的結果一致,但是第二個示例是通過JavaScript來提交表單的。服務器端根據HTTP請求中__EVENTTARGET的值來找到回發的控件,並觸發相應控件的服務器端事件。

 

太棒了太棒了太棒了

ExtAspNet特有的Ajax處理機制

我們都知道ExtAspNet的所有控件行為都是默認AJAX的,那個ExtAspNet是如何做到的呢?

其實道理也簡單,你可以打開ExtAspNet的源代碼,找到js/X/X.ajax.js文件。我們會發現如下的代碼:

   1:  X.ajax = {
   2:      hookPostBack: function () {
   3:          if (typeof (__doPostBack) != 'undefined') {
   4:              __doPostBack = x__doPostBack;
   5:          }
   6:      }
   7:  };
   8:   
   9:  function x__doPostBack(eventTarget, eventArgument) {
  10:      if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
  11:          theForm.__EVENTTARGET.value = eventTarget;
  12:          theForm.__EVENTARGUMENT.value = eventArgument;
  13:   
  14:          Ext.Ajax.request({
  15:              form: theForm.id,
  16:              url: document.location.href,
  17:              success: function (data) {
  18:                  // ....
  19:              },
  20:              failure: function (data) {
  21:                  // ...
  22:              }
  23:          });
  24:      }
  25:  }

 

在頁面初始化時,我們會調用X.ajax.hookPostBack,此函數內使用x__doPostBack函數來覆蓋頁面生成的__doPostBack函數,這樣原本所以對__doPostBack的調用都進入我們自己定義的處理函數中。在x__doPostBack處理函數中,我們不是調用表單的submit函數,而是調用Ext.Ajax.request來發起一次Ajax請求。

 

簡單來說,就是首先攔截__doPostBack函數,然后調用Ext.Ajax.request,是不是很簡單。

 

問題來了

我們介紹了Asp.Net的兩種回發機制,其中第二種使用的正是__doPostBack函數,但是第一種卻依賴於瀏覽器對type=submit的默認處理行為。這也導致在頁面中使用正常Asp.Net的Button,不會有ExtAspNet所特有的AJAX行為,怎么辦?

 

由於我們無法修改Asp.Net控件的實現代碼,也不可能向每個使用者傳授UseSubmitBehavior=false的小技巧,我們希望使用ExtAspNet的開發者能夠不假思索地快速開發,而不是陷在Asp.Net所設置的陷阱中。怎么辦?

 

迎刃而解

困難是難不倒我們這些勤勞善良的程序員,讓我來略施小技:

 

既然無法控制第一種提交方式,我們就來將其改造為第二種方式怎么樣:

   1:  makeAspnetSubmitButtonAjax: function (buttonId) {
   2:      function resetButton(button) {
   3:          button.set({
   4:              "type": "button"
   5:          });
   6:          button.addListener("click", function (event, el) {
   7:              __doPostBack(el.getAttribute("name"), "");
   8:              event.stopEvent();
   9:          });
  10:      }
  11:   
  12:      if (typeof (buttonId) === "undefined") {
  13:          Ext.each(Ext.DomQuery.select("input[type=submit]"), function (item, index) {
  14:              resetButton(Ext.get(item));
  15:          });
  16:      } else {
  17:          var button = Ext.get(buttonId);
  18:          if (button.getAttribute("type") === "submit") {
  19:              resetButton(button);
  20:          }
  21:      }
  22:  }

 

同時ExtAspNet還提供了一個參數來關閉這種行為,它就是PageManager的EnableAspnetSubmitButtonAjax屬性。

 

從這個小地方也體現了ExtAspNet細致入微、精益求精的態度,致力為廣大開發者打造一個方便快捷的Asp.Net控件庫。

 

ExtAspNet和AspNet的按鈕同時出現的示例

你可以在線查看這個示例的運行效果,其界面截圖如下所示:

image

 

ASPX的頁面標簽非常清晰:

   1:  <ext:PageManager ID="PageManager1" AjaxAspnetControls="aspBox,aspButton" runat="server" />
   2:  <ext:ContentPanel ID="ContentPanel1" runat="server" Width="500px" BodyPadding="5px" EnableBackgroundColor="true" ShowBorder="true" ShowHeader="true" Title="內容面板">
   3:      <ext:TextBox runat="server" Width="300px" ID="extBox"></ext:TextBox>
   4:      <asp:TextBox runat="server" Width="300px" ID="aspBox"></asp:TextBox>
   5:      <ext:Button ID="extButton" runat="server" CssClass="inline"
   6:      Text="ExtAsp.Net 按鈕" OnClick="extButton_Click"></ext:Button>
   7:      <asp:Button ID="aspButton" Text="Asp.Net 按鈕" runat="server"
   8:      OnClick="aspButton_Click" />
   9:  </ext:ContentPanel>

 

這里有兩個應用技巧:

1. 除非放在最外層的<form>標簽里,否則Asp.Net的標簽必須放在ContentPanel中。

2. 通過AjaxAspnetControls屬性來定義需要在回發是更新的Asp.Net控件,這個特性在《ExtAspNet秘密花園(四) — 每個頁面需要一個PageManager》有詳細的描述。

 

后端的C#代碼沒有任何特殊的地方:

   1:  protected void extButton_Click(object sender, EventArgs e) {
   2:      aspBox.Text = "Asp.Net 輸入框 - " + DateTime.Now.ToLongTimeString();
   3:      extBox.Text = "ExtAsp.Net 輸入框 - " + DateTime.Now.ToLongTimeString();
   4:      aspButton.Text = "Asp.Net 按鈕 - " + DateTime.Now.ToLongTimeString();
   5:      extButton.Text = "ExtAsp.Net 按鈕 - " + DateTime.Now.ToLongTimeString();
   6:  }
   7:   
   8:  protected void aspButton_Click(object sender, EventArgs e) {
   9:      aspBox.Text = "Asp.Net 輸入框 - " + DateTime.Now.ToLongTimeString();
  10:      extBox.Text = "ExtAsp.Net 輸入框 - " + DateTime.Now.ToLongTimeString();
  11:      aspButton.Text = "Asp.Net 按鈕 - " + DateTime.Now.ToLongTimeString();
  12:      extButton.Text = "ExtAsp.Net 按鈕 - " + DateTime.Now.ToLongTimeString();
  13:  }

 

至此,整個示例就完成。沒有任何讓人感到突兀的地方,而Asp.Net的按鈕控件卻自動擁有了ExtAspNet的AJAX特性。

 

小結

本章可以明顯看出ExtAspNet的對細節的追求和微創新,首先是對__doPostBack函數的攔截來實現Ajax,從而保證Asp.Net的默認調用方式不變,也為方便的切換Ajax與傳統的頁面回發埋下了伏筆;其次對於type=submit的按鈕,ExtAspNet通過PageManager的EnableAspnetSubmitButtonAjax屬性來將其轉化為第一種方式,從而保證了ExtAspNet的Ajax在所有情況的通用性。

下一篇文章,我們開始講述頁面中布局的使用,布局是用好ExtAspNet的關鍵,也是Asp.Net缺失的一個環節,所以不大容易理解,需要大家認真對待。

 

注:《ExtAspNet秘密花園》系列文章由三生石上原創,博客園首發,轉載請注明出處。文章目錄 官方論壇


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM