Introduction【介紹】
微軟AJax提出了與ASP.Net 2.0頁面服務器端生命周期事件相似的客戶端生命周期事件。這些客戶端事件使得我們能為傳統回送和異步回送(部分頁面刷新)都能定制自己的用戶界面。它們還可以在整個頁面生命周期期間幫助你管理和使用自定義的腳本。
這些客戶端事件在微軟的AJAX Libray的類中都被提出來了(我們可以在AJAX Libray的類中找到它們)。當加載一個帶有AJAX服務器控件時,這些類都會自動地實例化(instantiated?)。這些類提供了一些APIs以便我們能夠將事件綁定到事件提供處理程序。並且AJax Library是獨立於浏覽器的,所以你寫的代碼可以工作在所有支持的浏覽器。
關鍵的事件是初始化請求和異步回送的應用程序實例的 load 事件。當腳本在加載處理事件運行時,所有的腳本和組件都已經被加載並且是可用的。當使用了 UpdatePanel 控件部分頁面刷新時,所有客戶端事件中最關鍵的就是 PageRequestManager 類。這些客戶端事件使得你能夠實現某些場景。比如包括了: 撤銷回送,為一個回送設置更高的優先級,還可以使 UpdatePanel 在刷新的時候交互得更好。
這些事件對於我們創建頁面或寫組件都有很大的幫助。如果你是一個網頁開發人員,你可以為頁面在加載和卸載時使用定制的腳本。
向了解更多服務器端生命周期事件,可以參考 ASP.Net Page Life Cycle OvervIEw.
ClIEnt Classes【客戶端類】
在微軟AJAX類庫中提出了在AJax網頁的客戶端生命周期中兩個很主要的類: Application 類和 PageRequestManager 類。
當浏覽器請求一個有包含有 ScriptManager 控件的頁面時,Application 類就實例化了。Application 類和服務器端的 Page 控件類似,也是繼承自 Control 類,不過卻額外附加了一些功能(相比服務端事件)。類似的, Application 繼承了 Sys.COmponent 類,除此,還提供了很多在客戶端生命周期期間內的可操作事件。
如果一個頁面包含了一個 ScriptManager,並且還存在了一個或更多的 UpdatePanel 控件,那麼這個頁面就可以實現部分更新的效果了。如果是那樣的話,一個 PageRequestManager 類的實例對浏覽器是可用的了。PageRequestManager 提供的客戶端事件都是關於異步回送的。更多關於生成部分頁面的細節請參考:Partial-Page Rendering OvervIEw.
Adding Handlers for ClIEnt Events【為客戶端事件增加Handler】
現在通過使用 Application 和 PageRequestManager 類中的 add_eventname 和 reomve_eventname 方法來添加或移除事件。下面這個例子展示了如何添加一個操作(handler)名為 MyLoad 到 Application 對象的 init 事件。
Sys.Application.add_init(MyInit);
function MyInit(sender) {
}
Sys.Appplication.remove_init(MyInit);
注釋;這個例子只是展示了使用 add_eventname 和 remove_eventname 方法的語法。更多關於使用這個事件的細節將在後面的主題提供。
Handling the Application Load and Unload Events【操作Application的加載和卸載事件】
要操作 Application 對象的 load 和 unload 事件,不需要顯示地綁定到一個操作事件。相反地,你可以直接使用保留關鍵字 pageLoad 和 pageUnload 來創建一個函數。下面這個例子展示了如何為 Application 的 load 事件添加一個操作。
function pageLoad(sender, args) {
}
Events for Other ClIEnt Classes【其它客戶端類】
這個主題僅僅描述由 Application 和 PageRequestManager 類提供的事件。微軟的AJax類庫還包括了以下的類用於 DOM 元素事件的添加、清除和移除。這些類包括了:
有 Sys.UI.DomEvent.addHandler 方法或簡短寫法 $addHandler.
有 Sys.UI.DomEvent.clearHandlers 方法或簡短寫法 $clearHandlers.
有 Sys.UI.DomEvent.removeHandler 方法或簡短寫法 $removeHandler.
有關 DOM 原理提供的事件不是本主題討論的。
ClIEnt Events of the Application and PageRequestManager Classes【Application和PageRequestManager類的客戶端事件】
下面的表格列出了你可以在 AJax 的 ASP.Net 頁面使用的 Application 和 PageRequestManager 類的客戶端事件。事件發生的順序將在稍後的主題中進行討論。
Event
(事件名稱)
Description
(描述)
init Event
[初始化事件]
在所有腳本被加載後,在任何一個對象被創建之前引發該事件。如果你打算寫一個組件(腳本),init 事件提供了一個在生命周期內添加組件(腳本)到頁面的點。該組件可以被其它在生命周期內的腳本調用。如果你是一個網頁開發人員,在大多數的情況之下,建議用 load 事件來替代 init 事件來處理。
init 事件只在頁面開始生成時創建一次。後來的部分頁面刷新將不會引發 init 事件。
load Event
[加載事件]
該事件在所有腳本被加載後,並且由使用 $create 初始化的所有程序對象被創建後引發。該事件將被所有回送到服務器引發,這些回送也包括異步的回送。
如果你是網頁開發人員,你可以創建一個名為 pageLoad 的函數,該函數是由加載事件本身提供的。該 pageLoad 操作(handler)是在任何一個通過 add_load 方法被添加到 load 事件的操作後可以調用。
load 事件需要一個 Sys.ApplicationLoadEventArgs 對象作為 eventargs 參數。你可以通過該參數來決定頁面是否需要顯示部分刷新,還可以決定哪些組件應當在上一個引發 load 事件後被創建。
unload Event
[卸載事件]
在所有對象被釋放之前,在浏覽器的 window.unload 事件發生之前被引發。
你可以通過系統自身提供的一個名為 pageUnload 的函數來處理卸載事件。pageUnload 事件是在頁面在浏覽器中卸載時調用。在該事件發生期間,我們應當釋放由代碼占用的全部資源。
propertyChanged Event
[屬性改變事件]
當某組件的屬性發生改變時引發。應用程序對象是從 Component 類那裡繼承了這個事件。該事件僅在開發人員在設置一個屬性值的時候調用了 Sys.Component.raisePropertyChange 方法而引發的。
更多信息請查看 Defining Custom Component PropertIEs and Raising PropertyChanged Events.
屬性改變事件需要一個 Sys.applicationLoadEventArgs 對象作為 eventargs 參數。
disposing Event
[釋放事件]
該事件是在應用程序實例被釋放時引發的。應用程序對象從 Component 類繼承了該事件。
initializeRequest Event
[初始化請求事件]
該事件發生在一個異步請求開始時。你可以通過使用該事件來取消一個傳統的回送,例如讓一個異步回送獲得優先。
初始化請求事件需要一個 Sys.WebForms.InitializeRequestEventArgs 對象提供的 eventargs 參數。該對象提供了那些引起回送和暗藏的(underlying)請求的對象的有用的元素。該事件還暴露了 cancel 屬性。如果你設置 cancel 值為 true,一個新的回送將被撤銷。
beginRequest Event
[開始請求事件]
該事件是在一個回送到服務器的異步回送開始前引發。如果當前已經存在了一個回送進程,則會被停止(by using the abortPostBack method)。你可以使用該事件來設置請求的頭部或顯示一個有趣的(animation)提示在頁面中,表示該請求正在進行中。
該事件需要一個 Sys.WebForms.BeginRequestEventArgs 對象作為 eventargs 參數。該對象提供了引起回送的和暗藏的(underlying)請求對象的有用的元素。
pageLoading Event
[頁面正在加載事件]
當確定一個異步回送被服務器端接收後,在頁面任何內容被更新前引發。可以使用該事件來為需要更新的內容提供一個定制過渡效果。
該事件需要一個 Sys.WebForms.PageLoadingEventArgs 對象作為 eventargs 參數。該對象提供了最近的異步回送返回的結果關於哪些 panels 會被刪除和更新的有用的信息。
pageLoaded Event
[頁面加載完成事件]
在頁面所有內容被一個同步或異步回送結果刷新之後引發。在同步回送時,panels 只能被創建,但在異步回送時,panels 可以被創建和更新。可以通過使用該事件來管理一個為需要更新的內容定制的變化效果。
該事件需要一個 Sys.WebForms.PageLoadedEventArgs 對象作為 eventargs 參數。該對象提供了關於最近回送時的那些 panels 被更新和創建的有用的信息。
endRequest Event
[結束請求事件]
在響應了完成一個異步回送和頁面被更新後,或在請求過程中發生了錯誤後引發。如果發生了某個錯誤,頁面將不會被更新。通過使用這個事件來提供一個定制的錯誤提示給訪問者或登記到錯誤日志。
該事件需要一個 Sys.WebForms.EndRequestEventArgs 對象作為 eventargs 參數。該對象提供了有關被引發的錯誤和錯誤是否被處理的一些有用的信息。它還提供了有關相應對象的可用的信息。
Event Order Example 【事件順序的例子】
下面的這個例子展示了在一個存在有兩個嵌套的 UpdatePanel 控件的頁面的客戶端事件將被如何引發。請注意點擊父 panel 中的按鈕的和內嵌的 panel 中按鈕的區別。在父 panel 中的按鈕將引起父 panel 的更新,和嵌在其中的 panel 將被刪除並重新創建。內嵌 panel 的按鈕僅引起內嵌 panel 的更新。
頁面代碼:
1<%@ Page Language="C#" %>
2
3<!DOCTYPE html PUBLIC "-//W3C//DTD XHtml 1.0 Transitional//EN"
4 "http://www.w3.org/TR/xhtml1/DTD/xHtml1-transitional.dtd">
5
6<script runat="server">
7
8</script>
9
10<Html XMLns="http://www.w3.org/1999/xHtml" >
11<head runat="server">
12 <title>ClIEnt Event Example</title>
13 <style type="text/CSS">
14 #OuterPanel { width: 600px; height: 200px; border: 2px solid blue; }
15 #NestedPanel { width: 596px; height: 60px; border: 2px solid green;
16 margin-left:5 px; margin-right:5px; margin-bottom:5px;}
17 </style>
18</head>
19<body>
20 <form id="form1" runat="server">
21 <div>
22 <ASP:ScriptManager ID="ScriptManager1" runat="server">
23 <Scripts>
24 <ASP:ScriptReference Path="ClIEntEventTest.JS" />
25 </Scripts>
26 </ASP:ScriptManager>
27 <ASP:UpdatePanel ID="OuterPanel" UpdateMode="Conditional" runat="server">
28 <ContentTemplate>
29 Postbacks from inside the outer panel and inner panel are
30 asynchronous postbacks. PRM = Sys.WebForms.PageRequestManager. APP = Sys.Application.
31
32 <br /><br />
33 <ASP:Button ID="OPButton1" Text="Outer Panel Button" runat="server" />
34 Last updated on
35 <%= DateTime.Now.ToString() %>
36 <br /><br />
37
38 <ASP:UpdatePanel ID="NestedPanel" UpdateMode="Conditional" runat="server">
39 <ContentTemplate>
40 <ASP:Button ID="NPButton1" Text="Nested Panel 1 Button" runat="server" />
41 Last updated on
42 <%= DateTime.Now.ToString() %>
43 <br />
44 </ContentTemplate>
45 </ASP:UpdatePanel>
46 </ContentTemplate>
47 </ASP:UpdatePanel>
48
49 <input type="button" onclick="Clear();" value="Clear" />
50
51 <ASP:Button ID="FullPostBack" runat="server" Text="Full Postback" />
52 <a href="Test'>http://www.microsoft.com">Test Window Unload</a>
53 <br />
54 <span id="ClIEntEvents"></span>
55 </div>
56 </form>
57</body>
58</Html>
59
腳本代碼:
1// Hook up Application event handlers.
2var app = Sys.Application;
3app.add_load(ApplicationLoad);
4app.add_init(ApplicationInit);
5app.add_disposing(ApplicationDisposing);
6app.add_unload(ApplicationUnload);
7
8
9// Application event handlers for component developers.
10function ApplicationInit(sender) {
11 var prm = Sys.WebForms.PageRequestManager.getInstance();
12 if (!prm.get_isInAsyncPostBack())
13 {
14 prm.add_initializeRequest(InitializeRequest);
15 prm.add_beginRequest(BeginRequest);
16 prm.add_pageLoading(PageLoading);
17 prm.add_pageLoaded(PageLoaded);
18 prm.add_endRequest(EndRequest);
19 }
20 $get('ClIEntEvents').innerHtml += "APP:: Application init. <br/>";
21}
22function ApplicationLoad(sender, args) {
23 $get('ClIEntEvents').innerHtml += "APP:: Application load. ";
24 $get('ClIEntEvents').innerHtml += "(isPartialLoad = " + args.get_isPartialLoad() + ")<br/>";
25}
26function ApplicationUnload(sender) {
27 alert('APP:: Application unload.');
28}
29function ApplicationDisposing(sender) {
30 $get('ClIEntEvents').innerHtml += "APP:: Application disposing. <br/>";
31
32}
33// Application event handlers for page developers.
34function pageLoad() {
35 $get('ClIEntEvents').innerHtml += "PAGE:: Load.<br/>";
36}
37
38function pageUnload() {
39 alert('Page:: Page unload.');
40}
41
42// PageRequestManager event handlers.
43function InitializeRequest(sender, args) {
44 $get('ClIEntEvents').innerHtml += "<hr/>";
45 $get('ClIEntEvents').innerHtml += "PRM:: Initializing async request.<br/>";
46}
47function BeginRequest(sender, args) {
48 $get('ClIEntEvents').innerHtml += "PRM:: Begin processing async request.<br/>";
49}
50function PageLoading(sender, args) {
51 $get('ClIEntEvents').innerHtml += "PRM:: Loading results of async request.<br/>";
52 var updatedPanels = printArray("PanelsUpdating", args.get_panelsUpdating());
53 var deletedPanels = printArray("PanelsDeleting", args.get_panelsDeleting());
54
55 var message = "-->" + updatedPanels + "<br/>-->" + deletedPanels + "<br/>";
56
57 document.getElementById("ClIEntEvents").innerHtml += message;
58}
59function PageLoaded(sender, args) {
60 $get('ClIEntEvents').innerHtml += "PRM:: Finished loading results of async request.<br/>";
61 var updatedPanels = printArray("PanelsUpdated", args.get_panelsUpdated());
62 var createdPanels = printArray("PaneslCreated", args.get_panelsCreated());
63
64 var message = "-->" + updatedPanels + "<br/>-->" + createdPanels + "<br/>";
65
66 document.getElementById("ClIEntEvents").innerHtml += message;
67}
68function EndRequest(sender, args) {
69 $get('ClIEntEvents').innerHtml += "PRM:: End of async request.<br/>";
70}
71
72// Helper functions.
73function Clear()
74{
75 $get('ClIEntEvents').innerHtml = "";
76}
77function printArray(name, arr)
78{
79 var panels = name + '=' + arr.length;
80 if(arr.length > 0)
81 {
82 panels += "(";
83 for(var i = 0; i < arr.length; i++)
84 {
85 panels += arr[i].id + ',';
86 }
87 panels = panels.substring(0, panels.length - 1);
88 panels += ")";
89 }
90 return panels;
91}
92
運行效果 查看代碼
Event Order for Common ScenariOS【一般事件發生順序】
事件觸發順序還是要看在頁面中使用了什麼控件和發生了什麼類型的請求(初始化請求,傳統回送或是異步回送)。這部分將描述幾種常見情景的事件請求順序。
Initial Request 【初始化請求】
在一個頁面初始化請求過程中,少量的客戶端事件被引發。假設下面就是初始化請求的情景。
· 頁面包括一個 ScriptManager 控件,並且該控件的 SupportsPartialRendering 和 EnablePartialRendering 屬性都為 true。
· 請求是 GET 類型;
· 服務器能正常響應。
下面是客戶端事件發生的順序:
1、初始化請求發生給服務器。
2、客戶端接收到響應。
3、Application 實例引發 init 事件。
4、Application 實例引發 load 事件。
初始化事件僅在整個頁面生命周期過程中的應用程序實例化時發生一次。它不會被後來的異步回送所引發。在初始化請求(注意是請求)期間,沒有任何的 PageRequestManager 事件被引發。
Asynchronous Postback 【異步回送】
一個異步回送發送了一些頁面數據到服務器,並接收一個服務器端的響應,然後刷新頁面的一部分。假定下面一個異步回送的場景:
· 頁面包括一個 ScriptManager 控件,並且該控件的 SupportsPartialRendering 和 EnablePartialRendering 屬性都為 true。
· 頁面存在一個 UpdatePanel 控件,並且改控件的 ChildrenAsTriggers 屬性值為 true。
· 在 UpdatePanel 裡面有一個按鈕用於引發異步回送。
· 成功地從服務器端獲得響應。
下面是客戶端事件發生的順序:
1、點擊 UpdatePanel 控件中的按鈕時,引起了一個異步回送。
2、PageRequestManager 實例引發了 initializeRequest 事件。
3、PageRequestManager 實例引發了 beginRequest 事件。
4、請求被發送到服務器。
5、客戶端接收到了響應。
6、PageRequestManager 實例引發了 pageLoading 事件。
7、PageRequestManager 實例引發了 pageLoaded 事件。
8、Application 實例引發了 load 事件。
9、PageRequestManager 實例引發了 endRequest 事件。
請注意應用程序的 load 事件在 PageRequestManager 的 pageLoaded 事件之後,和 endRequest 事件之前。
Multiple Asynchronous Postbacks 【多個異步回送】
當之前的一個請求正在服務器端或浏覽器中運行時,用戶又發送了一個新的請求時,則發生了多個異步回送。假設下面的場景描述了多個異步回送的情況。
· 頁面包括一個 ScriptManager 控件,並且該控件的 SupportsPartialRendering 和 EnablePartialRendering 屬性都為 true。
· 頁面包含一個 UpdatePanel 控件。
· 在 UpdatePanel 中有一個引發異步回送的按鈕控件被點擊兩次。第二次的點擊發生在服務器端正在處理第一次點擊發起的請求。
· 獲得了從服務器端返回的對第一次請求的響應。
下面是客戶端事件發生的順序:
1、點擊 UpdatePanel 中的按鈕引發了一次異步回送。
2、PageRequestManager 實例引發了 initializeRequest 事件。
3、PageRequestManager 實例引發了 beginRequest 事件。
4、請求被發送到服務器。
5、客戶端接收到了響應。
6、按鈕被再次點擊,引發了第二次異步回送。
7、PageRequestManager 實例為第二次點擊引發了 initializeRequest 事件。
8、PageRequestManager 實例為第二次點擊引發了 beginRequest 事件。
9、第二次點擊的請求北伐掃到了服務器。
10、客戶端接收到了第二次點擊的響應。
11、PageRequestManager 實例引發了 pageLoading 事件。
12、PageRequestManager 實例引發了 pageLoaded 事件。
13、Application 實例引發了 load 事件。
14、PageRequestManager 實例引發了 endRequest 事件。
默認的異步回送行為是最近發生的異步回送優先級較高。如果兩個異步回送按順序發生,並且第一個異步回送仍在浏覽器處理中,則第一個回送被取消了。如果第一個回送已被發送到了服務器端,則服務器在第二個請求到來之前是不會返回第一個請求的。更多關於如何為異步回送設置優先級的詳情請參考 Giving Precedence to a Specific Asynchronous Postback.
Browsing Away from a Page 【浏覽其它頁】
當用戶從一個頁面訪問其它頁面時,當前的頁面會從浏覽器中卸載,因此你可以操作 unload 事件來釋放資源。假定下面模擬了這一場景。
· 頁面包括一個 ScriptManager 控件,並且該控件的 SupportsPartialRendering 和 EnablePartialRendering 屬性都為 true。
· 目標頁面存在。
下面是客戶端事件發生的順序:
1、發動一個請求新頁面的請求。
2、浏覽器獲得請求新頁面的響應。
3、Application 實例引發 unload 事件。
4、顯示了新頁面。
如果在請求新頁面時發生了錯誤,unload 事件依然會被引發,但是新頁面不會被顯示出來。
【完】