一、Ajax的前世今生
我一直覺得google是一家牛逼的公司,為什么這樣說呢?《舌尖上的中國》大家都看了,那些美食估計你是百看不厭,但是里邊我覺得其實也有這樣的一個哲學:關於食材,對於種食材的菜農來講,可能它的價值就是賣到市場上而已;而對於大廚們來講,卻可以像變魔術一樣將不起眼的食材變成美味佳餚。大廚們不擁有食材,但他們卻可以恰到好處的搭配使用它們,這就是他們的精明之處。而google同樣是IT界的大廚:java誕生了這么多年,卻沒有被充分利用,而google卻用它搞出來了震驚世界的Android; HTML、XML、Javascript這些個東東都不是google發明的吧,但卻是google卻用它們發明了Ajax, google earth、google suggest以及gmail等ajax技術的廣泛應用,向這個世界帶來了ajax技術,從此ajax與web再也不能分離。這里也向我們程序猿提了個醒:如果不能把所學的各種技術轉化為money或者生產力,那么一切都是扯淡!
精確的說,ajax並不能提高從服務器端下載數據的速度,而只是使這個等待不那么令人沮喪,這就是所謂的用戶體驗了,但就這一點就足以產生巨大的影響和震動,因為它已經革了c/s東東的命,它無疑是WEB時代的寵兒~
Ajax的給我們帶來的好處大家基本上都深有體會,略表一二:
1、最大的一點是頁面無刷新,在頁面內與服務器通信,給用戶的體驗非常好。
2、使用異步方式與服務器通信,不需要打斷用戶的操作,具有更加迅速的響應能力。
3、可以把以前一些服務器負擔的工作轉嫁到客戶端,利用客戶端閑置的能力來處理,減輕服務器和帶寬的負擔,節約空間和寬帶租用成本。並且減輕服務器的負擔,ajax的原則是“按需取數據”,可以最大程度的減少冗余請求,和響應對服務器造成的負擔。
4、基於標准化的並被廣泛支持的技術,不需要下載插件或者小程序。
缺點也有,但是瑕不掩瑜,所以還是要用!ASP.NET MVC作為微軟的當家利器自然也要擁抱Ajax了,這里就說說他們之間那些事兒!
二、ASP.NET MVC之Ajax
這里不會用原生的Ajax的,其實我連說都不想說,土的掉渣,更別提那個微軟自己的那個已經玩完的Ajax框架了,所以下面的Ajax都不是原生的。
1、基於AjaxHelper的Ajax
MVC框架本身提供了AjaxHelper類用於Ajax異步請求,所以如果你想省事,就用這種方式吧~
AjaxHelper幫助器方法:
| Helper method |
Description |
| Ajax.ActionLink |
Creates a hyperlink to a controller action that fires an Ajax request when clicked |
| Ajax.RouteLink |
Similar to Ajax.ActionLink, but generates a link to a particular route instead of a named controller action |
| Ajax.BeginForm |
Creates a form element that submits its data to a particular controller action using Ajax |
| Ajax.BeginRouteForm | Similar to Ajax.BeginForm, but creates a form that sub- mits its data to a particular route instead of a named control- ler action |
| Ajax.GlobalizationScript | Creates an HTML script element that references a script that contains culture information |
| Ajax.JavaScriptStringEncode | Encodes a string to make sure that it can safely be used inside JavaScript |
上面的方法貌似很多,但是實際開發中用到的就兩個幫助器方法而已:
Ajax.ActionLink()和Ajax.BeginForm()
這里有個問題:怎樣讓項目知道我們用的是MVC自帶的Ajax呢?
SO EASY:
A、在Web.config里邊配置:
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
B、在頁面中引用下面的js類庫即可:
@section scripts{ <script type="text/javascript" src=" @Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")"></script> }
一般更為常見的是在布局頁/Views/Shared/_Layout.cshtml 中引入,例如:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>@ViewBag.Title</title>
<script src="~/Scripts/jquery-1.8.2.min.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script>
</head>
<body>
@RenderBody()
</body>
</html>
Ajax.ActionLink():
向客戶端輸出一個鏈接地址,當單擊這個鏈接時可以Ajax調用Controller中的方法,Ajax.ActionLink()方法有許多重載,下面是其重載之一:
public static string ActionLink(this AjaxHelper ajaxHelper, string linkText, string actionName, object routeValues, AjaxOptions ajaxOptions);
linkText:是顯示在客戶端的文本
actionName:是Action的名字,默認情況下我們會使用當前的Controller。
routeValues:將傳入到Controller中方法的參數
ajaxOptions:配置Ajax的一些選項
| Confirm | 獲取或設置提交請求之前,顯示在確認窗口中的消息。 |
| HttpMethod |
獲取或設置 HTTP 請求方法(“Get”或“Post”)。 |
| InsertionMode |
獲取或設置指定如何將響應插入目標 DOM 元素的模式。 |
| LoadingElementId | 獲取或設置加載 Ajax 函數時要顯示的 HTML 元素的 id 特性。 |
| OnBegin |
獲取或設置更新頁面之前,恰好調用的 JavaScript 函數的名稱。 |
| OnComplete |
獲取或設置實例化響應數據之后但更新頁面之前,要調用的 JavaScript 函數。 |
| OnFailure |
獲取或設置頁面更新失敗時,要調用的 JavaScript 函數。 |
| OnSuccess |
獲取或設置成功更新頁面之后,要調用的 JavaScript 函數。 |
| UpdateTargetId |
獲取或設置要使用服務器響應來更新的 DOM 元素的 ID。 |
| Url |
獲取或設置要向其發送請求的 URL。 |
備注:
- OnComplete和OnSuccess的區別:OnComplete是獲取了Http請求時引發的,此時頁面還沒有進行更新,OnSuccess是在頁面已經更新后引發的。
- 當加載數據須要花較長時候,為了避免假死狀況,該當給用戶一個反饋信息,如“正在加載...”字樣。在 MVC 的 Unobtrusive Ajax 中經用AjaxOptions選項的 LoadingElementId 和 LoadingElementDuration 兩個屬性可輕松做到這一點,例如下面的設置:
AjaxOptions ajaxOpts = new AjaxOptions { UpdateTargetId = "tableBody", Url = Url.Action("GetPeopleData"), LoadingElementId = "loading", LoadingElementDuration = 1000, };
- 對於URL,如果我們設置如下:
AjaxOptions ajaxOpts = new AjaxOptions { UpdateTargetId = "tableBody", Url = Url.Action("GetPeopleData") };
然后查看它生成的 form 屬性:
<form id="form0" action="/People/GetPeople" method="post" data-ajax-url="/People/GetPeopleData" data-ajax-="#tableBody"
data-ajax-mode="replace" data-ajax="true">
它生成了兩個 Url,分別為 action 屬性 和 data-ajax-url 屬性的值,前者是 Ajax.BeginForm() 辦法按照當前 controller 和 action 名稱生成的,后者是 AjaxOptions 的 Url 屬性生成的。當瀏覽器沒有禁用 JavaScript 時,Unobtrusive Ajax JS庫會獲取 data-ajax-url 屬性的值作為 Url 產生 ajax 懇求。當瀏覽器禁用了 JavaScript 時,天然 action 屬性的值決定了默示提交的 Url,自然訪問該頁面。固然局部未能刷新,但不會讓用戶體驗很差。
使用Html.ActionLink方法的一個栗子:
@Ajax.ActionLink("點擊我", "getEntry", new { id = item.Id }, new AjaxOptions
{ HttpMethod = "Post", UpdateTargetId = "detailsID", InsertionMode = InsertionMode.Replace })
說明:“點擊我”是生產的超鏈接文字;“getEntry”是當前控制器的Action方法;id = item.Id是向Action方法傳遞的參數;HttpMethod = "Post", 說明Ajax請求是post方式的;UpdateTargetId = "detailsID"說明了要更新的html塊的Id標記元素;InsertionMode = InsertionMode.Replace說明是替換ID為detailsID的元素里邊的內容。
實際應用:
(1)使用Ajax.ActionLink請求返回值為 Json格式的Controller方法
在Index.cshtml中使用ActionLink,如下:
@Ajax.ActionLink("點擊我", "JsonDetails", new { id = item.Id },
new AjaxOptions { HttpMethod = "Post", InsertionMode = InsertionMode.Replace, OnSuccess = "Show" })
相應的Controller:
public ActionResult JsonDetails(int id = 0) { GuestbookEntry entry = _db.Entries.First(c => c.Id == id); return Json(entry, JsonRequestBehavior.AllowGet); }
同時需要在Index.cshtml中添加請求成功的相應js函數Show,以便更新ID屬性為detailsID的DIV內容:
<script type="text/javascript"> function Show(data) { $("#detailsID").html("姓名:" + data.Name + " 消息:" + data.Message); } </script>
(2)使用Ajax.ActionLink 請求返回值為PartialView格式的Controller方法
在Index.cshtml中
@Ajax.ActionLink("AjaxPartialView", "Details", new { id = item.Id },
new AjaxOptions { HttpMethod = "Get", UpdateTargetId = "detailsID" })
相應的Controller:
public ActionResult Details(int id = 0) { GuestbookEntry entry = _db.Entries.First(c => c.Id == id); if (Request.IsAjaxRequest()) { return PartialView(entry); } return View(entry); }
在這里我們使用Request.IsAjaxRequest()來判斷是否為Ajax請求,如果是則返回PartialView,否則返回View。最后,返回的內容會直接更新到ID屬性為detailsID的DIV中。
Ajax.BeginForm
這個方法用於異步提交表單,比如一個新增信息的頁面Create.cshtml,下面的代碼會使表單以Ajax方式提交
@model MvcApplication5.Models.GuestbookEntry <script type="text/javascript" src=" @Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")"></script> <script type="text/javascript"> function success(data) { alert(data); } </script> @{ ViewBag.Title = "Create"; } <h2>Create</h2> @using (Ajax.BeginForm(new AjaxOptions { HttpMethod="Post", OnSuccess = "success" })) { @Html.ValidationSummary(true) <fieldset> <legend>GuestbookEntry</legend> <div class="editor-label"> @Html.LabelFor(model => model.Name) </div> <div class="editor-field"> @Html.EditorFor(model => model.Name) @Html.ValidationMessageFor(model => model.Name) </div> <div class="editor-label"> @Html.LabelFor(model => model.Message) </div> <div class="editor-field"> @Html.EditorFor(model => model.Message) @Html.ValidationMessageFor(model => model.Message) </div> <p> <input type="submit" value="Create" /> </p> </fieldset> }
控制器的代碼如下:
[HttpPost] public ActionResult Create(GuestbookEntry entry) { if (ModelState.IsValid) { entry.DateAdded = DateTime.Now; _db.Entries.Add(entry); _db.SaveChanges(); return Content("New Entry successfully added."); } else { return View(); } }
注:
貌似上面的Ajax方法很方便,但是它的工作原理可能大家不是很清楚,這里就大概說一下吧~
當調用 Ajax.BeginForm 方法后,經由選項 AjaxOptions 對象設置的屬性將會被轉化成 form 表單的屬性,這些屬性以 data-ajax 開首,如本示例生成的 form 表單:
<form action="/GuestBook/Create" data-ajax="true" data-ajax-mode="replace" data-ajax-="#tableBody" id="form0" method="post">
當 Create.cshtml 視圖加載完成並浮現 Html 頁面時,jquery.unobtrusive-ajax.js 庫會尋找所有 data-ajax == true的元素,然后按照其它以 data-ajax 開頭的屬性值,jQuery 庫中的函數將知道如何去執行 Ajax 請求。
2、基於JQuery的Ajax
(1)使用JQuery的Ajax請求返回值為 Json格式的Controller方法
原理就是用JQuery的Ajax方法請求Action方法,返回值設為JSON,然后對JSON數據進行處理,例如用js函數進行處理
舉個栗子:
<script type="text/javascript" language="javascript"> $(function(){ GetRoomInfoList();
}); function GetRoomInfoList() { showDivLoading();//異步加載數據時的浮層 $.ajax({ type: "Post", url: "@Url.Content("~/Room/GetRoomInfoShipId")",//異步請求的URL,就是Room控制器方法GetRoomInfoShipId(long shipId) dataType: "json",//要求返回數據為JSON格式 data:{shipId:$("#ShipIdForSearch").val()},//異步請求的參數 success: function(data){ $("#RoomInfoListTable").empty(); //清空里面的所有內容 $.each(data, function(i, item){ //用js拼字符串處理數據,這里是顯示所有房型列表信息 var str="<tr>"; str+=" <td>"; str+=" <span style=\" width:150px;display:block;white-space:nowrap; overflow:hidden; text-overflow:ellipsis;\">"; str+=item.BaseRoomId; str+=" </span>" str+=" </td>"; str+=" <td>"; str+=" <span style=\" width:150px;display:block;white-space:nowrap; overflow:hidden; text-overflow:ellipsis;\">"; str+=item.ShipId; str+=" </span>" str+=" </td>"; str+=" <td>"; str+=" <span style=\" width:150px;display:block;white-space:nowrap; overflow:hidden; text-overflow:ellipsis;\">"; str+=item.RoomType; str+=" </span>" str+=" </td>"; str+=" <td>"; str+=" <span style=\" width:150px;display:block;white-space:nowrap; overflow:hidden; text-overflow:ellipsis;\">"; str+=item.RoomName; str+=" </span>" str+=" </td>"; str+="</tr>"; $("#RoomInfoListTable").append(str);
}); } }); }
(2)使用JQuery的Ajax 請求返回值為PartialView格式的Controller方法
假設有這樣的一個Model:
namespace MvcApplication1.Models { public class Team { public string Preletter { get; set; } public string Name { get; set; } } }
通過JQuery異步加載分部視圖,Home/Index.cshtml:
@{ ViewBag.Title = "Index"; Layout = "~/Views/Shared/_Layout.cshtml"; } <h2>Index</h2> <div> <a href="#" id="a">通過jQuery異步</a> <br/> </div> <div id="result"> </div> @section scripts { <script type="text/javascript"> $(function() { $('#a').click(function() { $.ajax({ url: '@Url.Action("Index","Home")', data: { pre: 'B' }, type: 'POST', success: function(data) { $('#result').empty().append(data); } }); return false; }); }); </script> }
HomeController控制器中:
using System.Collections.Generic; using System.Linq; using System.Web.Mvc; using MvcApplication1.Models; namespace MvcApplication1.Controllers { public class HomeController : Controller { public ActionResult Index() { return View(); } [HttpPost] public ActionResult Index(string pre) { var result = GetAllTeams().Where(t => t.Preletter == pre).ToList(); ViewBag.msg = "通過jQuery異步方式到達這里~~"; return PartialView("TeamY", result); } private List<Team> GetAllTeams() { return new List<Team>() { new Team(){Name = "巴西隊", Preletter = "B"}, new Team(){Name = "克羅地亞隊", Preletter = "K"}, new Team(){Name = "巴拉圭", Preletter = "B"}, new Team(){Name = "韓國", Preletter = "K"} }; } } }
分部視圖TeamY.cshtml:
@model IEnumerable<MvcApplication1.Models.Team> @{ var result = string.Empty; foreach (var item in Model) { result += item.Name + ","; } } @ViewBag.msg.ToString() <br/> @result.Substring(0,result.Length - 1)
3、基於JQuery的表單異步提交
舉個栗子吧:
<script type="text/javascript"> $(document).ready(function () { $("#form1").submit(function (event) { event.preventDefault();//阻止默認提交事件,改用JS處理提交事件
$.ajax({
type:"Post//表單提交類型
url: "@Url.Content("~/User/Create")",//表單提交的Action方法
data:$("#form1").serialize(), //序列化表單的值為字符串,前提是表單里邊的輸入標簽都要有name屬性才可以,序列化后的形式大概是這樣的:a=1&b=2&c=3&d=4&e=5
success:function(msg){
$("#result").html(msg);
}
});
return false;
});
}); </script>
但是我覺得如果表單提交的數據少的話,可以用這種,如果多的話,就沒有必要了,用MVC自帶的更好
三、如何提高Ajax性能
1、適當使用緩存機制
2、使用CDN內容分發來訪問Jquery腳本:
(1)自己公司架設CDN服務器
(2)使用第三方公司的,比如微軟,谷歌等公司的CDN,但有時候不太靠譜
3、JS/CSS文件的打包合並(Bundling)及壓縮(Minification)
將多個JS或CSS文件打包合並成一個文件,並在網站發布之后進行壓縮,從而減少HTTP請求次數,提高網絡加載速度和頁面解析速度。壓縮功能實現了對javascript腳本和CSS進行壓縮的功能,它能夠去除腳本或樣式中不必要的空白和注釋,同時能夠優化腳本變量名的長度
例如在BundleConfig.cs里面配置捆綁js和css文件:
using System.Web; using System.Web.Optimization; namespace MvcExample { public class BundleConfig { // For more information on Bundling, visit http://go.microsoft.com/fwlink/?LinkId=254725 public static void RegisterBundles(BundleCollection bundles) { bundles.Add(new ScriptBundle("~/bundles/jquery").Include( "~/Scripts/jquery-{version}.js")); bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.css")); } } }
記得在Global.asax中注冊一下:
BundleConfig.RegisterBundles(BundleTable.Bundles);
頁面引用時可以這樣引用:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>@ViewBag.Title</title>
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/jquery")
@RenderSection("scripts", required: false)
</head>
<body>
@RenderBody()
</body>
</html>
啟用JS/CSS文件壓縮合並:
- Web.config中配置
<compilation debug="false" targetFramework="4.0" />
- 在BundleConfig.cs或Global.asax中添加以下代碼即可:
BundleTable.EnableOptimizations = true;
4、最好將js腳本文件放在view頁面下面一點
關於ASP.NET MVC和Ajax的故事,暫且講到這里吧!
