ASP.NET MVC 早期版本 (Preview/RC) 未內建完整 AJAX Helper,開發者需自行撰寫 JavaScript 攔截連結點擊與表單提交,轉為 AJAX 請求並更新局部頁面。本文記錄使用 `MvcAjax` 輔助庫實現無阻塞 AJAX 導航與表單提交的模式。
var mvcAjax = {
// 連結點擊 → AJAX GET
get: function(link, evt) {
evt.preventDefault();
var url = link.href;
var target = link.getAttribute('data-target') || '#main-content';
var loader = link.getAttribute('data-loader') || '#ajax-loader';
$(loader).show();
$.get(url, function(html) {
$(target).html(html);
$(loader).hide();
// 重新綁定新內容中的連結/表單
mvcAjax.rebind(target);
}).fail(function() {
$(loader).hide();
alert('請求失敗');
});
},
// 表單提交 → AJAX POST
submit: function(form, evt) {
evt.preventDefault();
var $form = $(form);
var url = $form.attr('action');
var target = $form.attr('data-target') || '#main-content';
var loader = $form.attr('data-loader') || '#ajax-loader';
$(loader).show();
$.post(url, $form.serialize(), function(html) {
$(target).html(html);
$(loader).hide();
mvcAjax.rebind(target);
}).fail(function(xhr) {
$(loader).hide();
if (xhr.status === 400) {
// 驗證錯誤:回傳含錯誤訊息的 Partial View
$(target).html(xhr.responseText);
mvcAjax.rebind(target);
} else {
alert('提交失敗');
}
});
},
// 重新綁定動態載入內容中的連結/表單
rebind: function(containerSelector) {
$(containerSelector + ' a[data-ajax="true"]').off('click').on('click', function(e) {
mvcAjax.get(this, e);
});
$(containerSelector + ' form[data-ajax="true"]').off('submit').on('submit', function(e) {
mvcAjax.submit(this, e);
});
}
};
// 頁面載入時初始綁定
$(function() {
mvcAjax.rebind('body');
});
public class ProductsController : Controller
{
// 連結點擊:GET /Products/List/Category1?page=2
public ActionResult List(string category, int page = 1)
{
var model = _service.GetProducts(category, page);
if (Request.IsAjaxRequest()) // 或 Request.Headers["X-Requested-With"] == "XMLHttpRequest"
return PartialView("_ProductList", model); // 只回傳片段
return View(model); // 完整頁面
}
// 表單提交:POST /Products/Create
[HttpPost]
public ActionResult Create(ProductViewModel model)
{
if (!ModelState.IsValid)
{
// 驗證失敗:回傳含錯誤的 PartialView
return PartialView("_CreateForm", model);
}
_service.Create(model);
return PartialView("_SuccessMessage", new { Message = "建立成功" });
}
}
@foreach (var cat in Model.Categories)
{
-
@Html.ActionLink(cat.Name, "List", "Products",
new { category = cat.Slug },
new {
data_ajax = "true", // 啟用 AJAX
data_target = "#product-list", // 更新目標區塊
data_loader = "#loader" // 載入指示器
})
}
@Html.Partial("_ProductList", Model.Products)
@using (Html.BeginForm("Create", "Products", FormMethod.Post,
new { data_ajax = "true", data_target = "#product-form", data_loader = "#loader" }))
{
@Html.Partial("_CreateForm", new ProductViewModel())
}
@Html.Partial("_CreateForm", new ProductViewModel())
@model IEnumerable
@foreach (var p in Model) {
@p.Name
@p.Price
@Html.ActionLink("編輯", "Edit", new { id = p.Id }, new { data_ajax = "true", data_target = "#product-form" })
}
@model ProductViewModel
@using (Html.BeginForm("Create", "Products", FormMethod.Post, new { data_ajax = "true" }))
{
@Html.ValidationSummary(true)
@Html.LabelFor(m => m.Name) @Html.TextBoxFor(m => m.Name) @Html.ValidationMessageFor(m => m.Name)
@Html.LabelFor(m => m.Price) @Html.TextBoxFor(m => m.Price) @Html.ValidationMessageFor(m => m.Price)
}
ASP.NET MVC 3+ 內建 `jquery.unobtrusive-ajax.js`,透過 `data-ajax="true"` 等屬性聲明式啟用:
@Html.ActionLink("刪除", "Delete", new { id = 1 },
new { data_ajax = "true", data_ajax_method = "POST", data_ajax_confirm = "確定刪除?" })
@using (Ajax.BeginForm("Create", "Products", new AjaxOptions
{
HttpMethod = "POST",
UpdateTargetId = "product-form",
InsertionMode = InsertionMode.Replace,
OnSuccess = "onCreateSuccess",
OnFailure = "onCreateFailure"
}))
{ ... }
**新專案請直接使用 `jquery.unobtrusive-ajax` 或 `fetch`/`axios` 配合 Web API 回傳 JSON**,避免維護自訂 AJAX 库。
// 在 mvcAjax.get/submit 成功後
if (window.history.pushState) {
window.history.pushState({ url: url }, '', url);
document.title = $(html).filter('title').text() || '頁面';
}
// 監聽瀏覽器前進/後退
window.onpopstate = function(e) {
if (e.state && e.state.url) {
$.get(e.state.url, function(html) {
$('#main-content').html(html);
mvcAjax.rebind('#main-content');
});
}
};
掌握 AJAX 連結/表單模式,是打造流暢單頁應用體驗 (SPA) 的關鍵基礎,即使現代前端框架 (Vue/React) 接管 View 層,Controller 端的 PartialView/JSON 回傳邏輯依然通用。