先定義我所謂的「AJAX 表單傳送」:意指撰寫 JavaScript 蒐集 HTML 表單欄位,再藉由 XHR 傳送到伺服器端,取代傳統的 Postback。其優點包含送單時畫面不閃動、沒有重新載入網頁的延遲以及傳輸運算成本、表單處理失敗使用者輸入狀態不變方便修改重送... 等等,近年來 AJAX 表單已成網頁操作設計主流。相較之下,傳統 Postback 方式(指用<form action="…">配合<input type="submit">或<button>按鈕送單的做法)雖然使用者體驗略遜一籌,但寫法簡單,在一些要求不高,殺雞不必用牛刀的場合,仍是省時省力的好選擇。

另一種我會繼續使用 Postback 的情境發生於修現有網站的 Bug,總不能看不習慣就怒把 Postback 表單都翻寫成 AJAX 版,叫你割痔瘡卻搞成切盲腸,母湯喔母湯~

依據實務經驗,Postback 表單有個棘手問題是送單出錯時得恢復欄位原本輸入狀態以便使用者修正重試,使用 ASP.NET WebForm 的 ViewState 可以解決部分問題,但遇到有 JavaScript 參與互動時,要完整還原的難度便提高許多。我有時會使出 Postback 時傳回 <script>alert(msg);history.go(-1);</script> 退回前一頁的技巧,大部部情況下瀏覽器會神奇地保留原本的輸入內容,但遇到由 JavaScript 控制的部分還是很容易破功。舉個例了:

假設網頁有兩個<intput type="text">,一個手動輸入,另一個由 JavaScript 填入:

<html>
<body>
<form action="post1.aspx" method="post">
	<input type="text" name="userId" value="" />
	<input type="text" name="seed" value="" />
	<button>Submit Form</button>
</form>
<script>
document.querySelector("input[name=seed]").value = Math.random();
</script>
</body>
</html>

伺服器模擬送單出錯,傳回一段 JavaScript,alert 錯誤訊息後用 history.go(-1) 退回上一頁:

<%@Page Language="C#"%>
<script runat="server">
void Page_Load(object sender, EventArgs e)
{
	Response.Write("<script>alert('Something wrong!');history.go(-1);</" + "script>");
	Response.End();
}
</script>

如以下展示,退回上一頁時,手動輸入的內容還在,但亂數欄位已重新產生。

如果不想改寫 $.post() 抓欄位呼叫 post1.aspx,其實還有一招取巧做法 - 利用 <form> 的 target 將傳回結果嵌入 <iframe>,傳回結果以 JavaScript 呼叫 parent 的函式或直接修改 parent 的 DOM。如此,輸入頁面的所有欄位狀態不因送出表單而變動,能簡單實現類似 AJAX 送單的效果。

做法是在頁面放置一個 <iframe>,取名 name="result",並透過 style="display:none" 隱形,而 <form> 則加上 target="result" 指定將 Postback 結果顯示於 <iframe>:

<html>
<body>
<iframe name="result" style="display:none"></iframe>
<form action="post2.aspx" target="result" method="post">
	<input type="text" name="userId" value="" />
	<input type="text" name="seed" value="" />
	<button>Submit Form</button>
	<div id="msg" style="color:red"></div>
</form>
<script>
document.querySelector("input[name=seed").value = Math.random();
function showMessage(msg) {
	document.querySelector("#msg").innerHTML = msg;
}
</script>
</body>
</html>

Post.aspx 小做修改,傳回結果改傳一小段 JavaScript 程式,將呼叫 parent 預先寫好的函式顯示執行結果:

<%@Page Language="C#"%>
<script runat="server">
void Page_Load(object sender, EventArgs e)
{
	Response.Write(
		"<script>parent.showMessage('Something wrong! - " + Guid.NewGuid() + "');</" 
		+ "script>");
	Response.End();
}
</script>

如下所示,不必大費周章就能輕鬆用 Postback 實現類似 AJAX 送單的效果囉!

Trick of using HTML form postback to simulate AJAX post request.


Comments

Be the first to post a comment

Post a comment