AJAX 用戶端生命週期事件
更新:2007 年 11 月
具備 AJAX 能力的 ASP.NET 網頁會引發與 ASP.NET 2.0 Web 網頁相同的伺服器生命週期事件,此外也會引發用戶端生命週期事件。用戶端事件可讓您自訂使用者介面 (UI),以用於回傳與非同步回傳 (網頁局部更新)。用戶端事件也可協助您在瀏覽器的頁面存留期 (Lifetime) 內,管理自訂指令碼元件。
用戶端事件是由 Microsoft AJAX Library 中的類別所引發。當頁面包含 ASP.NET AJAX 伺服器控制項時,這些類別會自動執行個體化。用戶端類別則會提供 API 讓您繫結至事件,並提供那些事件的處理常式。因為 Microsoft AJAX Library 與瀏覽器分開運作,所以您撰寫的處理常式程式碼,在所有支援的瀏覽器上的運作方式完全相同。
初始要求 (GET 要求) 的關鍵事件與同步回傳為 Application 執行個體的 load 事件。執行 load 事件處理常式中的指令碼時,所有指令碼與元件都會載入並可供使用。啟用 UpdatePanel 控制項的相關部分頁面呈現時,關鍵用戶端事件為 PageRequestManager 類別的事件。這些事件可讓您處理許多常見案例。包括可以取消回傳、指定某個回傳的優先順序,以及在重新整理 UpdatePanel 控制項的內容時將其顯示為動畫。
無論您要建立頁面或撰寫元件,用戶端事件都非常有用。如果您是網頁開發人員,您可以提供自訂指令碼,在瀏覽器載入或卸載頁面時予以呼叫。
如需伺服器生命週期事件的詳細資訊,請參閱 ASP.NET 網頁存留週期概觀。
用戶端類別
在 ASP.NET AJAX Web 網頁的用戶端生命週期內引發事件的兩個主要 Microsoft AJAX Library 類別為 Application 和 PageRequestManager。
頁面包含 ScriptManager 控制項時,Application 類別便會在瀏覽器中執行個體化。Application 類別與 Page 伺服器控制項相似,該控制項衍生自 Control 類別,但提供其他功能以引發伺服器事件。同樣地,Application 類別衍生自 Sys.Component 類別,但會引發您能夠處理的用戶端生命週期事件。
如果頁面包含一個或多個 ScriptManager 控制項與多個 UpdatePanel 控制項,該頁面就能執行部分頁面更新 (如果啟用部分頁面呈現,且瀏覽器支援)。在該情況下,PageRequestManager 類別的執行個體會自動出現在瀏覽器中。PageRequestManager 類別會引發非同步回傳專用的用戶端事件。如需部分頁面呈現的詳細資訊,請參閱網頁局部呈現概觀。
加入用戶端事件的處理常式
若要新增或移除由 Application 和 PageRequestManager 類別所引發之事件的處理常式,請使用那些類別的 add_eventname 和 remove_eventname 方法。下列範例說明如何將名為 MyLoad 的處理常式,加入至 Application 物件的 init 事件。
Sys.Application.add_init(MyInit);
function MyInit(sender) {
}
Sys.Appplication.remove_init(MyInit);
Sys.Application.add_init(MyInit);
function MyInit(sender) {
}
Sys.Appplication.remove_init(MyInit);
注意事項: |
---|
此範例只示範 add_eventname 和 remove_eventname 方法的語法。有關如何處理特定事件,本主題稍後將提供詳細的資訊。 |
處理 Application Load 與 Unload 事件
若要處理 Application 物件的 load 和 unload 事件,您不需要將處理常式明確繫結至事件。反之,您可以建立使用保留名稱 pageLoad 和 pageUnload 的函式。下列範例說明如何使用這個方法,為 Application 物件的 load 事件加入處理常式。
function pageLoad(sender, args) {
}
function pageLoad(sender, args) {
}
其他用戶端類別的事件
本主題只說明由 Application 和 PageRequestManager 類別所引發的事件。Microsoft AJAX Library 也包含可供加入、清除及移除 DOM 項目事件處理常式的類別。這些類別包括下列各項:
本主題不討論由 DOM 項目所引發的事件。
Application 與 PageRequestManager 類別的用戶端事件
下表列出Application 和 PageRequestManager 類別的用戶端事件,您可以在具備 AJAX ASP.NET 能力的頁面上處理這些類別。本主題稍後將說明事件的引發順序。
事件 |
描述 |
---|---|
所有指令碼已載入之後,但尚未建立任何物件之前引發。如果您正在撰寫元件,init 事件會在生命週期內給您一個指標,指出要將元件要加入到頁面的位置。之後其他元件或頁面生命週期後期的指令碼就能使用該元件。如果您是網頁開發人員,在大部分狀況下,您應該使用 load 事件而非 init 事件。 init 事件只會在第一次呈現頁面時引發一次。後續的部分頁面更新並不會引發 init 事件。 |
|
所有指令碼已載入,且應用程式中所有使用 $create 建立的物件都已執行個體化之後引發。對伺服器的所有回傳都會引發 load 事件,包括非同步回傳。 如果您是網頁開發人員,您可以建立名為 pageLoad 的函式,以自動提供 load 事件的處理常式。當 add_load 方法將任何處理常式加入至 load 事件之後,就會呼叫 pageLoad 處理常式。 load 事件採用 eventargs 參數,此參數為 Sys.ApplicationLoadEventArgs 物件。您可以使用事件引數來判斷頁面是否因部分頁面更新而導致重新整理,以及自引發上一個 load 事件以來共建立了哪些元件。 |
|
在處置所有物件,瀏覽器視窗的 window.unload 事件發生之前引發。 如果您是網頁開發人員,您可以建立名為 pageUnload 的函式,以自動提供 unload 事件的處理常式。pageUnload 事件只會在從瀏覽器卸載頁面之前予以呼叫。在此事件期間,您應該釋出程式碼佔用的所有資源。 |
|
可能在元件屬性變更時引發。只有當元件開發人員在屬性 set 存取子中呼叫 Sys.Component.raisePropertyChange 方法時,才會引發此事件。如需詳細資訊,請參閱定義自訂元件屬性和引發 PropertyChanged 事件。 propertyChanged 事件會採用 eventargs 參數,此參數為 Sys.applicationLoadEventArgs 物件。 |
|
處置 Application 執行個體時引發。 |
|
開始非同步要求之前引發。您可以使用此事件來取消回傳,例如優先處理另一個非同步回傳。 initializeRequest 事件會採用 eventargs 參數,此參數為 Sys.WebForms.InitializeRequestEventArgs 物件。此物件使導致回傳的項目及基礎要求物件變成可使用,InitializeRequestEventArgs 也會公開 cancel 屬性。如果您將 cancel 設定為 true,就會取消新的回傳。 |
|
在非同步回傳開始及傳送該回傳至伺服器之前引發。如果已經開始處理某回傳,就會停止該回傳 (使用 abortPostBack 方法)。您可以使用此事件來設定要求標頭,或在頁面上顯示動畫以指出要求正在處理中。 beginRequest 事件會採用 eventargs 參數,此參數為 Sys.WebForms.BeginRequestEventArgs 物件。此物件使導致回傳的項目及基礎要求物件變成可使用。 |
|
收到來自伺服器對非同步回傳的回應之後、但更新頁面上任何內容之前引發。您可以使用此事件來提供已更新內容的自訂轉換效果。 pageLoading 事件會採用 eventargs 參數,此參數 Sys.WebForms.PageLoadingEventArgs 物件。此物件提供相關資訊以說明哪些面板將因最近一次非同步回傳而導致刪除或更新。 |
|
因同步或非同步回傳而導致重新整理頁面上的所有內容之後引發。對於同步回傳,只會建立面板,但對非同步回傳則會同時建立及更新面板。您可以使用此事件來管理已更新內容的自訂轉換效果。 pageLoaded 事件會採用 eventargs 參數,此參數 Sys.WebForms.PageLoadedEventArgs 物件。此物件提供相關資訊以說明哪些面板已在最近一次回傳中更新及建立。 |
|
已處理非同步回傳的回應且已更新頁面之後,或當發生錯誤時在回應處理期間引發。如果發生錯誤,頁面就不會更新。請使用此事件為使用者提供自訂的錯誤告知,或者記錄錯誤。 endRequest 事件會採用 eventargs 參數,此參數為 Sys.WebForms.EndRequestEventArgs 物件。此物件提供已發生的錯誤及該錯誤是否已處理的相關資訊。它也使回應物件變成可使用。 |
事件順序範例
下列範例說明在頁面上引發的用戶端事件,該頁面包含兩個 UpdatePanel 控制項,其中一個巢狀位於另一個之內。您將會注意到按一下父面板中之按鈕與巢狀面板中之按鈕的不同之處。父面板中的按鈕會導致更新父面板,而巢狀面板則被刪除並重新建立。巢狀面板中的按鈕只會導致更新巢狀面板。
<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script >
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head >
<title>Client Event Example</title>
<style type="text/css">
#OuterPanel { width: 600px; height: 200px; border: 2px solid blue; }
#NestedPanel { width: 596px; height: 60px; border: 2px solid green;
margin-left:5 px; margin-right:5px; margin-bottom:5px;}
</style>
</head>
<body>
<form id="form1" >
<div>
<asp:ScriptManager ID="ScriptManager1" >
<Scripts>
<asp:ScriptReference Path="ClientEventTest.js" />
</Scripts>
</asp:ScriptManager>
<asp:UpdatePanel ID="OuterPanel" UpdateMode="Conditional" >
<ContentTemplate>
Postbacks from inside the outer panel and inner panel are
asynchronous postbacks. PRM = Sys.WebForms.PageRequestManager. APP = Sys.Application.
<br /><br />
<asp:Button ID="OPButton1" Text="Outer Panel Button" />
Last updated on
<%= DateTime.Now.ToString() %>
<br /><br />
<asp:UpdatePanel ID="NestedPanel" UpdateMode="Conditional" >
<ContentTemplate>
<asp:Button ID="NPButton1" Text="Nested Panel 1 Button" />
Last updated on
<%= DateTime.Now.ToString() %>
<br />
</ContentTemplate>
</asp:UpdatePanel>
</ContentTemplate>
</asp:UpdatePanel>
<input type="button" onclick="Clear();" value="Clear" />
<asp:Button ID="FullPostBack" Text="Full Postback" />
<a href="https://www.microsoft.com">Test Window Unload</a>
<br />
<span id="ClientEvents"></span>
</div>
</form>
</body>
</html>
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script >
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head >
<title>Client Event Example</title>
<style type="text/css">
#OuterPanel { width: 600px; height: 200px; border: 2px solid blue; }
#NestedPanel { width: 596px; height: 60px; border: 2px solid green;
margin-left:5 px; margin-right:5px; margin-bottom:5px;}
</style>
</head>
<body>
<form id="form1" >
<div>
<asp:ScriptManager ID="ScriptManager1" >
<Scripts>
<asp:ScriptReference Path="ClientEventTest.js" />
</Scripts>
</asp:ScriptManager>
<asp:UpdatePanel ID="OuterPanel" UpdateMode="Conditional" >
<ContentTemplate>
Postbacks from inside the outer panel and inner panel are
asynchronous postbacks. PRM = Sys.WebForms.PageRequestManager. APP = Sys.Application.
<br /><br />
<asp:Button ID="OPButton1" Text="Outer Panel Button" />
Last updated on
<%= DateTime.Now.ToString() %>
<br /><br />
<asp:UpdatePanel ID="NestedPanel" UpdateMode="Conditional" >
<ContentTemplate>
<asp:Button ID="NPButton1" Text="Nested Panel 1 Button" />
Last updated on
<%= DateTime.Now.ToString() %>
<br />
</ContentTemplate>
</asp:UpdatePanel>
</ContentTemplate>
</asp:UpdatePanel>
<input type="button" onclick="Clear();" value="Clear" />
<asp:Button ID="FullPostBack" Text="Full Postback" />
<a href="https://www.microsoft.com">Test Window Unload</a>
<br />
<span id="ClientEvents"></span>
</div>
</form>
</body>
</html>
// Hook up Application event handlers.
var app = Sys.Application;
app.add_load(ApplicationLoad);
app.add_init(ApplicationInit);
app.add_disposing(ApplicationDisposing);
app.add_unload(ApplicationUnload);
// Application event handlers for component developers.
function ApplicationInit(sender) {
var prm = Sys.WebForms.PageRequestManager.getInstance();
if (!prm.get_isInAsyncPostBack())
{
prm.add_initializeRequest(InitializeRequest);
prm.add_beginRequest(BeginRequest);
prm.add_pageLoading(PageLoading);
prm.add_pageLoaded(PageLoaded);
prm.add_endRequest(EndRequest);
}
$get('ClientEvents').innerHTML += "APP:: Application init. <br/>";
}
function ApplicationLoad(sender, args) {
$get('ClientEvents').innerHTML += "APP:: Application load. ";
$get('ClientEvents').innerHTML += "(isPartialLoad = " + args.get_isPartialLoad() + ")<br/>";
}
function ApplicationUnload(sender) {
alert('APP:: Application unload.');
}
function ApplicationDisposing(sender) {
$get('ClientEvents').innerHTML += "APP:: Application disposing. <br/>";
}
// Application event handlers for page developers.
function pageLoad() {
$get('ClientEvents').innerHTML += "PAGE:: Load.<br/>";
}
function pageUnload() {
alert('Page:: Page unload.');
}
// PageRequestManager event handlers.
function InitializeRequest(sender, args) {
$get('ClientEvents').innerHTML += "<hr/>";
$get('ClientEvents').innerHTML += "PRM:: Initializing async request.<br/>";
}
function BeginRequest(sender, args) {
$get('ClientEvents').innerHTML += "PRM:: Begin processing async request.<br/>";
}
function PageLoading(sender, args) {
$get('ClientEvents').innerHTML += "PRM:: Loading results of async request.<br/>";
var updatedPanels = printArray("PanelsUpdating", args.get_panelsUpdating());
var deletedPanels = printArray("PanelsDeleting", args.get_panelsDeleting());
var message = "-->" + updatedPanels + "<br/>-->" + deletedPanels + "<br/>";
document.getElementById("ClientEvents").innerHTML += message;
}
function PageLoaded(sender, args) {
$get('ClientEvents').innerHTML += "PRM:: Finished loading results of async request.<br/>";
var updatedPanels = printArray("PanelsUpdated", args.get_panelsUpdated());
var createdPanels = printArray("PaneslCreated", args.get_panelsCreated());
var message = "-->" + updatedPanels + "<br/>-->" + createdPanels + "<br/>";
document.getElementById("ClientEvents").innerHTML += message;
}
function EndRequest(sender, args) {
$get('ClientEvents').innerHTML += "PRM:: End of async request.<br/>";
}
// Helper functions.
function Clear()
{
$get('ClientEvents').innerHTML = "";
}
function printArray(name, arr)
{
var panels = name + '=' + arr.length;
if(arr.length > 0)
{
panels += "(";
for(var i = 0; i < arr.length; i++)
{
panels += arr[i].id + ',';
}
panels = panels.substring(0, panels.length - 1);
panels += ")";
}
return panels;
}
// Hook up Application event handlers.
var app = Sys.Application;
app.add_load(ApplicationLoad);
app.add_init(ApplicationInit);
app.add_disposing(ApplicationDisposing);
app.add_unload(ApplicationUnload);
// Application event handlers for component developers.
function ApplicationInit(sender) {
var prm = Sys.WebForms.PageRequestManager.getInstance();
if (!prm.get_isInAsyncPostBack())
{
prm.add_initializeRequest(InitializeRequest);
prm.add_beginRequest(BeginRequest);
prm.add_pageLoading(PageLoading);
prm.add_pageLoaded(PageLoaded);
prm.add_endRequest(EndRequest);
}
$get('ClientEvents').innerHTML += "APP:: Application init. <br/>";
}
function ApplicationLoad(sender, args) {
$get('ClientEvents').innerHTML += "APP:: Application load. ";
$get('ClientEvents').innerHTML += "(isPartialLoad = " + args.get_isPartialLoad() + ")<br/>";
}
function ApplicationUnload(sender) {
alert('APP:: Application unload.');
}
function ApplicationDisposing(sender) {
$get('ClientEvents').innerHTML += "APP:: Application disposing. <br/>";
}
// Application event handlers for page developers.
function pageLoad() {
$get('ClientEvents').innerHTML += "PAGE:: Load.<br/>";
}
function pageUnload() {
alert('Page:: Page unload.');
}
// PageRequestManager event handlers.
function InitializeRequest(sender, args) {
$get('ClientEvents').innerHTML += "<hr/>";
$get('ClientEvents').innerHTML += "PRM:: Initializing async request.<br/>";
}
function BeginRequest(sender, args) {
$get('ClientEvents').innerHTML += "PRM:: Begin processing async request.<br/>";
}
function PageLoading(sender, args) {
$get('ClientEvents').innerHTML += "PRM:: Loading results of async request.<br/>";
var updatedPanels = printArray("PanelsUpdating", args.get_panelsUpdating());
var deletedPanels = printArray("PanelsDeleting", args.get_panelsDeleting());
var message = "-->" + updatedPanels + "<br/>-->" + deletedPanels + "<br/>";
document.getElementById("ClientEvents").innerHTML += message;
}
function PageLoaded(sender, args) {
$get('ClientEvents').innerHTML += "PRM:: Finished loading results of async request.<br/>";
var updatedPanels = printArray("PanelsUpdated", args.get_panelsUpdated());
var createdPanels = printArray("PaneslCreated", args.get_panelsCreated());
var message = "-->" + updatedPanels + "<br/>-->" + createdPanels + "<br/>";
document.getElementById("ClientEvents").innerHTML += message;
}
function EndRequest(sender, args) {
$get('ClientEvents').innerHTML += "PRM:: End of async request.<br/>";
}
// Helper functions.
function Clear()
{
$get('ClientEvents').innerHTML = "";
}
function printArray(name, arr)
{
var panels = name + '=' + arr.length;
if(arr.length > 0)
{
panels += "(";
for(var i = 0; i < arr.length; i++)
{
panels += arr[i].id + ',';
}
panels = panels.substring(0, panels.length - 1);
panels += ")";
}
return panels;
}
常見案例的事件順序
事件順序視頁面上使用哪些控制項及所做要求的類型 (初始要求、回傳或非同步回傳) 而定。本節說明數種常見案例的事件順序。
初始要求
在頁面的初始要求期間,會引發有限次數的用戶端事件。初始要求的狀況假設如下:
頁面包含一個 ScriptManager 控制項,且控制項的 SupportsPartialRendering 和 EnablePartialRendering 屬性皆為 true。
要求為 GET 要求。
伺服器成功傳回回應。
下列用戶端事件會依此順序發生:
傳送初始要求至伺服器。
用戶端收到回應。
Application 執行個體會引發 init 事件。
Application 執行個體會引發 load 事件。
Application 執行個體的 init 事件只會在瀏覽器的頁面存留期間內引發一次。後續的非同步回傳並不會引發此事件。在初始要求期間,不會引發任何 PageRequestManager 事件。
非同步回傳
非同步回傳會傳送一些頁面資料至伺服器、接收回應,然後更新部分頁面。非同步回傳的狀況假設如下:
頁面包含一個 ScriptManager 控制項,且控制項的 SupportsPartialRendering 和 EnablePartialRendering 屬性皆為 true。
頁面包含一個 UpdatePanel 控制項,且控制項的 ChildrenAsTriggers 屬性為 true。
UpdatePanel 控制項內部的按鈕會啟始非同步回傳。
伺服器成功傳回回應。
下列用戶端事件會依此順序發生:
按一下 UpdatePanel 內部的按鈕,該按鈕會啟始非同步回傳。
PageRequestManager 執行個體會引發 initializeRequest 事件。
PageRequestManager 執行個體會引發 beginRequest 事件。
傳送要求至伺服器。
用戶端收到回應。
PageRequestManager 執行個體會引發 pageLoading 事件。
PageRequestManager 執行個體會引發 pageLoaded 事件。
Application 執行個體會引發 load 事件。
PageRequestManager 執行個體會引發 endRequest 事件。
如需詳細資訊,請參閱使用 PageRequestManager 事件。
請注意,Application 執行個體的 load 事件,是在 PageRequestManagerpageLoaded 事件之後、及其 endRequest 事件之前引發的。
多個非同步回傳
當使用者在伺服器或瀏覽器處理完先前啟始的要求之前,在啟始新要求時,可能會發生多個非同步回傳。多個非同步回傳的狀況假設如下:
頁面包含一個 ScriptManager 控制項,且控制項的 SupportsPartialRendering 和 EnablePartialRendering 屬性皆為 true。
頁面包含一個 UpdatePanel 控制項。
按兩次 UpdatePanel 控制項內的按鈕,該按鈕會啟始非同步回傳。按第二次的時間,就是伺服器正在處理第一次按該按鈕所啟始的要求時。
伺服器成功傳回第一個要求的回應。
下列用戶端事件會依此順序發生:
按一下 UpdatePanel 內部的按鈕,該按鈕會啟始非同步回傳。
PageRequestManager 執行個體會引發 initializeRequest 事件。
PageRequestManager 執行個體會引發 beginRequest 事件。
傳送要求至伺服器。
再按一下按鈕,該按鈕會啟始第二個非同步回傳。
PageRequestManager 執行個體會引發第二次按鈕的 initializeRequest 事件。
PageRequestManager 執行個體會引發第一次按鈕的 endRequest 事件。
PageRequestManager 執行個體會引發第二次按鈕的 beginRequest 事件。
傳送第二次按鈕所啟始的要求至伺服器。
收到第二次按鈕的回應。
PageRequestManager 執行個體會引發 pageLoading 事件。
PageRequestManager 執行個體會引發 pageLoaded 事件。
Application 執行個體會引發 load 事件。
PageRequestManager 執行個體會引發 endRequest 事件。
非同步回傳的預設行為會以最新的非同步回傳佔有最高優先權。如果連續發生兩個非同步回傳,且瀏覽器尚在處理第一個回傳,則會取消第一個回傳。如果第一個回傳已傳送至伺服器,則伺服器會在收到第二個要求時進行處理,且不會傳回第一個要求。如需如何指定特定非同步回傳之優先順序的詳細資訊,請參閱指定特定非同步回傳的優先順序。
離開頁面進行瀏覽
當使用者離開頁面進行瀏覽時,瀏覽器會卸載目前頁面,而且您可以處理 unload 事件以釋出資源。離開頁面進行瀏覽的狀況假設如下:
頁面包含一個 ScriptManager 控制項,且控制項的 SupportsPartialRendering 和 EnablePartialRendering 屬性皆為 true。
目標頁面存在。
下列用戶端事件會依此順序引發:
啟始新頁面的要求。
瀏覽器收到新頁面的回應。
Application 執行個體會引發 unload 事件。
接著會出現新頁面。
如果新頁面的要求中發生錯誤,仍會引發 unload 事件,但不會顯示新頁面。