【譯】MVC3 20個秘方-(13)使用Ajax Helper 提高用戶體驗
問題
當你點擊鏈接時,整個的網頁都被重新加載。尤其是你僅僅一小點內容需要被更新時,這將被感覺是一個很慢的過程。
解決方案
更新之前創建的HTML.ActionLink 去調用ajax 幫助類。Ajax.ActionLink 僅僅去重新加載那些發生變化的內容。
討論
MVC提供了幾個給力的幫助類。到目前為止,這本書中已經廣泛的應用了HTML Helper。在過去創建的所有view中,HTML helper至少都使用過一次。在這個秘方中,我們將使用AjaxHelper類替換掉Book/Index中的HtmlHelper 類。
實現Ajax需要一點額外的設置才可以使用。通常情況下我發現這個額外的工作,可以打消開發人員使用它的念頭。我要讓大家知道,額外的安裝設置是值得的,因為帶來的好處是獲得了更好的用戶體驗,這是非常值得努力去做的。
步驟從web.config開始。2個關鍵的地方要被設置成true. ClientValidationEnabled 和UnobtrusiveJavaScriptEnabled。
譯者:原書中代碼引入了整個web.config文件。我們只需要到appSettings節點下即可找到這兩個keys。
<appSettings>
<add key="webpages:Version" value="1.0.0.0" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
接下來的步驟是我們要引入幾個javascript 文件。我們要在里shared 的layout文件夾里完成這件事,因為幾乎我們創建所有的view時都會引用它(布局模板)。在Views/Shared/_Layout.cshtml 文件的<head>標簽中。我們引入2個javascript 文件,代碼如下:
<head>
<title>@ViewBag.Title</title>
<link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
<script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")"type="text/javascript"></script>
</head>
這些文件被自動的包含在基礎MVC3應用程序中。(譯者:你可以從scripts文件夾中找到他們)。以上的步驟完成AJAX的核心配置。接下來,我們要更新Book/index view。在下邊的例子里,三個filter link和sortable header link將用Ajax.ActionLink 替換Html.ActionLink.代碼如下:
@model PagedList.IPagedList<MvcApplication.Models.Book>
@if (IsAjax)
{
Layout = null;
}
<h2>
Title</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<p>
Show:
@if (ViewBag.CurrentFilter != "")
{
@Ajax.ActionLink("All", "Index",
new
{
sortOrder = ViewBag.CurrentSortOrder,
Keyword = ViewBag.CurrentKeyword
},
new AjaxOptions { UpdateTargetId = "main" })
}
else
{
@:All
}
|
@if (ViewBag.CurrentFilter != "NewReleases")
{
@Ajax.ActionLink("New Releases", "Index", new
{
filter = "NewReleases",
sortOrder = ViewBag.CurrentSortOrder,
Keyword = ViewBag.CurrentKeyword
},
new AjaxOptions { UpdateTargetId = "main" })
}
else
{
@:New Releases
}
|
@if (ViewBag.CurrentFilter != "ComingSoon")
{
@Ajax.ActionLink("Coming Soon", "Index", new
{
filter = "ComingSoon",
sortOrder = ViewBag.CurrentSortOrder,
Keyword = ViewBag.CurrentKeyword
},
new AjaxOptions { UpdateTargetId = "main" })
}
else
{
@:Coming Soon
}
</p>
@using (Html.BeginForm())
{
@:Search: @Html.TextBox("Keyword")<input type="submit" value="Search" />
}
@Html.Partial("_Paging")
<table>
<tr>
<th>
@Ajax.ActionLink("Title", "Index", new
{
sortOrder = ViewBag.TitleSortParam,
filter = ViewBag.CurrentFilter,
Keyword = ViewBag.CurrentKeyword
},
new AjaxOptions { UpdateTargetId = "main" })
</th>
<th>
@Ajax.ActionLink("Isbn", "Index", new
{
sortOrder = ViewBag.IsbnSortParam,
filter = ViewBag.CurrentFilter,
Keyword = ViewBag.CurrentKeyword
},
new AjaxOptions { UpdateTargetId = "main" })
</th>
<th>
Summary
</th>
<th>
@Ajax.ActionLink("Author", "Index", new
{
sortOrder = ViewBag.AuthorSortParam,
filter = ViewBag.CurrentFilter,
Keyword = ViewBag.CurrentKeyword
},
new AjaxOptions { UpdateTargetId = "main" })
</th>
<th>
Thumbnail
</th>
<th>
@Ajax.ActionLink("Price", "Index", new
{
sortOrder = ViewBag.PriceSortParam,
filter = ViewBag.CurrentFilter,
Keyword = ViewBag.CurrentKeyword
},
new AjaxOptions { UpdateTargetId = "main" })
</th>
<th>
@Ajax.ActionLink("Published", "Index", new
{
sortOrder = ViewBag.PublishedSortParam,
filter = ViewBag.CurrentFilter,
Keyword = ViewBag.CurrentKeyword
},
new AjaxOptions { UpdateTargetId = "main" })
</th>
<th>
</th>
</tr>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.Isbn)
</td>
<td>
@Html.DisplayFor(modelItem => item.Summary)
</td>
<td>
@Html.DisplayFor(modelItem => item.Author)
</td>
<td>
@Html.DisplayFor(modelItem => item.Thumbnail)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
@Html.DisplayFor(modelItem => item.Published)
</td>
<td>
@Html.ActionLink("Edit","Edit", new { id = item.ID }) |
@Html.ActionLink("Details","Details", new { id = item.ID }) |
@Html.ActionLink("Delete","Delete", new { id = item.ID })
</td>
</tr>
}
</table>
@Html.Partial("_Paging")
譯者:上邊代碼標綠的地方就是我們更新的地方。
我們做的關鍵的事就是在ActionLink的最后一個參數添加了AjaxOptions。這意味著一旦用戶點擊了這個AJAX link,AJAX請求的結果將會更新id 是“main”的html元素。如果你看看share文件夾中早期我們修改的layout文件,你會注意到有一個<div>的id 是“main”。實際上,這個div就是@Renderbody()的容器,它是一個view輸出的地方。
另外一個重要的事就是我們在view的頂端加了一個AJAX是否完成的檢測。如果請求通過AJAX完成,layout設置成null。這是一個非常重要的因素,因為如果它沒完成,Ajax請求的結果將會包含不僅僅是view的result,也會包含整個layout,而沒必要再去替換掉layout了。
為了完成這個示例,share文件夾下的_Paging也要使用Ajax helper更新,代碼如下:
<p>
@if (Model.HasPreviousPage)
{
@Ajax.ActionLink("<< First", "Index", new
{
page = 1,
sortOrder = ViewBag.CurrentSortOrder,
filter = ViewBag.CurrentFilter
},
new AjaxOptions { UpdateTargetId ="main" })
@Html.Raw(" ");
@Html.ActionLink("< Prev", "Index", new
{
page = Model.PageNumber - 1,
sortOrder = ViewBag.CurrentSortOrder,
filter = ViewBag.CurrentFilter
}, new AjaxOptions { UpdateTargetId ="main" })
}
else
{
@:<< First
@Html.Raw(" ");
@:< Prev
}
@if (Model.HasNextPage)
{
@Ajax.ActionLink("Next >", "Index", new
{
page = Model.PageNumber + 1,
sortOrder = ViewBag.CurrentSortOrder,
filter = ViewBag.CurrentFilter
}, new AjaxOptions { UpdateTargetId ="main" })
@Html.Raw(" ");
@Ajax.ActionLink("Last >>", "Index", new
{
page = Model.PageCount,
sortOrder = ViewBag.CurrentSortOrder,
filter = ViewBag.CurrentFilter
}, new AjaxOptions { UpdateTargetId ="main" })
}
else
{
@:Next >
@Html.Raw(" ")
@:Last >>
}
</p>
現在,當用戶點擊一個link 改變book 列表時,整個的頁面不會被重新載入并且僅僅是圖書列表被更新。這提供了一個更好、更快的用戶體驗。
而且,如果客戶端不支持javascript(例如,一個搜索引擎訪問),這個link將像以前一樣工作。它將重新載入整個頁面。
另請參見

浙公網安備 33010602011771號