Asp.Net MVC4系列--进阶篇之AJAX
2014-04-16 23:59
411 查看
本章将开始介绍MVC中Ajax的使用
以一个非Ajax版本开始
Controller
public class PeopleController : Controller { private readonly Person[] _personData = { new Person {FirstName = "Iori",LastName = "Lan", Role = Role.Admin}, new Person {FirstName = "Edwin", LastName= "Sanderson", Role = Role.Admin}, new Person {FirstName = "John",LastName = "Griffyth", Role = Role.User}, new Person {FirstName = "Tik",LastName = "Smith", Role = Role.User}, new Person {FirstName = "Anne",LastName = "Jones", Role = Role.Guest} }; public ActionResult Index() { return View("List"); } public ActionResult GetPeople() { return View("List",_personData); } [HttpPost] public ActionResult GetPeople(string selectedRole) { if (selectedRole == null || selectedRole == "All") { returnView("List",_personData); } var selected = (Role)Enum.Parse(typeof(Role), selectedRole); return View("List",_personData.Where(p => p.Role ==selected)); } }
Model
public class Person { public string FirstName { get; set; } public string LastName { get; set; } public Role Role { get; set; } } public enum Role { Admin, User, Guest }
View
@{ Layout = null; } @using MVCAjax.Models @model IEnumerable<Person> @{ ViewBag.Title = "GetPeople"; } <h2>Get People</h2> <table> <thead><tr><th>First</th><th>Last</th><th>Role</th></tr></thead> <tbody> @foreach (var p in Model) { <tr> <td>@p.FirstName</td> <td>@p.LastName</td> <td>@p.Role</td> </tr> } </tbody> </table> @using (Html.BeginForm()) { <div> @Html.DropDownList("selectedRole",new SelectList( new []{"All"}.Concat(Enum.GetNames(typeof(Role))))) <button type="submit">Submit</button> </div> }
测试:
验证请求类型
在IE中打开F12->Network ,我们可以看到请求的发起者是click操作,因为不是xmlHttpRequest,因而不是ajax请求使用Ajax重构代码
配置Unobstrusiveajax
打开web.config
确保这一行在appconfig节点中:<add key="UnobtrusiveJavaScriptEnabled" value="true" />
打开App_Start/BundleConfig.cs,确保已添加(默认已添加):
bundles.Add(newScriptBundle("~/bundles/jquery").Include( "~/Scripts/jquery-{version}.js")); bundles.Add(new ScriptBundle("~/bundles/jqueryui").Include( "~/Scripts/jquery-ui-{version}.js")); bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include( "~/Scripts/jquery.unobtrusive*", "~/Scripts/jquery.validate*"));
原因:我们需要的是jquery.1.7.1.js 和jquery.unobstrucsive-ajax.min.js,这两个包已经包含了,在layout中render就可以了。
打开_layout.cshtml
在<head>中render 这两个包:@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/jqueryval")
注意:在View确保没有把@{layout=null},否则layout没有应用导致没有renderbundle,以致于无法render需要的script。
Controller 添加Action:
public ActionResult AjaxGetPeople() { return View("AjaxList"); } public PartialViewResult GetPeoplePartial(string selectedRole = "All") { IEnumerable<Person> data = _personData; if(selectedRole != "All") { var selected = (Role)Enum.Parse(typeof(Role), selectedRole); data =_personData.Where(p => p.Role == selected); } return PartialView("PeoplePartialList",data); }
添加PartialViewPeoplePartialList.cshtml :
@using MVCAjax.Models @model IEnumerable<Person> @foreach (Person p in Model) { <tr> <td>@p.FirstName</td> <td>@p.LastName</td> <td>@p.Role</td> </tr> }
添加View: AjaxList.cshtml :
@using MVCAjax.Models @model string @{ ViewBag.Title = "GetPeople"; var ajaxOpts = new AjaxOptions { UpdateTargetId = "tableBody" }; } <h2>Get People</h2> <table> <thead><tr><th>First</th><th>Last</th><th>Role</th></tr></thead> <tbody id="tableBody"> @Html.Action("GetPeoplePartial", new {selectedRole= Model }) </tbody> </table> @using(Ajax.BeginForm("GetPeoplePartial",ajaxOpts)) { <div> @Html.DropDownList("selectedRole", new SelectList( new []{"All"}.Concat(Enum.GetNames(typeof(Role))))) <button type="submit">Submit</button> </div> }
运行:
F12->Network 查看请求
可以看到,initiator 为XMLHttpRequest ,验证了请求确实是Ajax。
分析Obstrusivejavascript 工作原理
<form action="/People/GetPeoplePartial" data-ajax="true" data-ajax-mode="replace" data-ajax-update="#tableBody" id="form0" method="post">
这是MVC Framework生成的form tag,对于unobsrutive javascript 来说,他关心的是data-ajax=”true”和data-ajax开头的attribute,首先找到所有data-ajax=”true”的form,然后根据data-ajax-mode找到data-ajax-update的id(注意,unobstrusivejs 基于Jquery,需要加#)完成局部刷新。
Ajax Options
以下列出一些常用的AjaxOptions :Confirm | 发起请求前弹出确认框,指定确认框的文字 |
HttpMethod | 请求类型:POST,GET,PUT,DELETE等等 |
InsertionMode | Replace,Before,After, 默认为Replace |
LoadingElementId | 请求发出后,收到Server回应前弹出一个loading的div,这里指定div id |
LoadingElementDuration | 设置loading Div最多显示多少秒 |
UpdateTargetId | 要局部更新的container id |
Url | 发请求的url |
Loading 和Confirmation
现在稍作改动,给例子加一个Confirmation和loading
准备loading的div和css
Css:
<style type="text/css"> .popup_background { z-index: 10; background-color: grey; position: fixed; top: 0; bottom: 0; left: 0; right: 0; opacity: 0.4; } .popup_loading { z-index: 11; font-size: 50px; top: 400px; left: 600px; position: absolute; } </style>
仅作为演示,我hard-code了loading div的位置,实际项目中需要调整
Html:
<div id="loading" class="popup_background" style="display:none"> <div class="popup_loading"> <p>Loading...</p> </div> </div>
在AjaxOption中指定Id
var ajaxOpts = new AjaxOptions { UpdateTargetId = "tableBody" , Confirm = "Sure?", LoadingElementDuration = 2000, LoadingElementId = "loading" };
在Controller中模拟一个长时间的任务
Sleep 3秒private void MockLongTimeProcessing() { Thread.Sleep(3000); }
在partialview中调用一下
public PartialViewResult GetPeoplePartial(string selectedRole ="All") { MockLongTimeProcessing(); ... }
运行,查看效果:
Ajax链接
Ajax链接的生成很简单。稍作改动,看一下ajax链接的使用方法,在View(AjaxList.cshtml)中添加:
<div> @foreach (string role in Enum.GetNames(typeof(Role))) { <div class="ajaxLink"> @Ajax.ActionLink(role,"GetPeoplePartial", new {selectedRole= role}, ajaxOpts) </div> } </div>
这样就可以了,其实就是调用Ajax.ActionLink函数,设置链接的文字,Action,以及参数,最后一个是AjaxOption,我们用的是前面一个demo的。
添加对Json的支持
改动Controller
和前面的步骤一样,添加两个Action,一个是服务第一次加载页面的 请求,我们返回View,一个是Ajax过来的,我们需要返回JsonResult:public ActionResult JsonList() { return View("JsonList"); } public JsonResult GetPeopleJson(string selectedRole = "All") { IEnumerable<Person> data = _personData; if (selectedRole !="All") { var selected =(Role)Enum.Parse(typeof(Role), selectedRole); data =_personData.Where(p => p.Role == selected); } return Json(data,JsonRequestBehavior.AllowGet); }
添加View:
JsonList.cshtml@using MVCAjax.Models @model string @{ ViewBag.Title = "GetPeople"; var ajaxOpts = new AjaxOptions { UpdateTargetId = "tableBody", }; } <script type="text/javascript"> function processData(data) { var target =$("#tableBody"); target.empty(); for (var i = 0; i <data.length; i++) { var person = data[i]; target.append("<tr><td>" + person.FirstName +"</td><td>" + person.LastName +"</td><td>" + person.Role +"</td></tr>"); } } </script> <h2>Get Json List</h2> <table> <thead><tr><th>First</th><th>Last</th><th>Role</th></tr></thead> <tbody id="tableBody"> @Html.Action("GetPeoplePartial", new {selectedRole = Model }) </tbody> </table> <div> @foreach (string role in Enum.GetNames(typeof(Role))) { <div class="ajaxLink"> @Ajax.ActionLink(role, "GetPeople", new {selectedRole = role}, new AjaxOptions { Url = Url.Action("GetPeopleJson", new {selectedRole = role}), OnSuccess = "processData" }) </div> } </div>
为了简便演示,仅仅展示Json部分,笔者拿掉了Loading和Confirm的部分。
代码分析
代码的核心在于OnSuccess = "processData" 。当Ajax请求成功时,指向processData函数,在这个函数里面,我们拿到id(JqueryId)为#tableBody的表单,清空,手动拼html,并用jquery添加到这个html control中。这部分可以优化,可以选择handlebar.js,knockout.js 等js template。
在table body中调用了@Html.Action("GetPeoplePartial",new {selectedRole = Model }),和前面的原因一样,为了第一次加载时显示出所有人员列表。
另外,AjaxOptions中还有其他Callback类型;
OnBegin : 发请求前
OnFailure :请求失败
OnSuccess :请求成功
OnComplete :请求完毕
相关文章推荐
- bootstrap-data-target触发模态弹出窗元素的data使用 data-toggle与data-target的作用 深入ASP.NET MVC之九:Ajax支持 Asp.Net MVC4系列--进阶篇之AJAX
- Asp.Net MVC4 系列-- 进阶篇之路由(1)
- Asp.Net MVC4 系列-- 进阶篇之路由(1)
- Asp.Net MVC4 系列--进阶篇之View
- Asp.Net MVC4 系列--进阶篇之路由 (2)
- Asp.Net MVC4系列--进阶篇之Helper(1)
- Asp.Net MVC4 系列--进阶篇之Controller(2)
- Asp.Net MVC4 系列--进阶篇之Model(1)
- Asp.Net MVC4系列--进阶篇之Helper(2)
- Asp.Net MVC4 系列--进阶篇之Model(2)
- HTTP系列 -- AJAX 进阶
- Asp.Net MVC4 系列-- 进阶篇之路由
- Asp.Net MVC4 系列-- 进阶篇之路由(1)
- Asp.Net MVC4 系列--进阶篇之Helper(2)
- Asp.Net MVC4 系列--进阶篇之路由 (2)
- Asp.Net MVC4 系列-- 进阶篇之路由(1)
- Asp.Net MVC4 系列-- 进阶篇之路由(1)【转】
- Asp.Net MVC4系列--进阶篇之Helper(1)
- Asp.Net MVC4 系列--进阶篇之路由 (2)
- 【AJAX进阶】——概念