ASP.NET MVC 4 (八) URL链接和Ajax帮助函数
使用帮助函数创建链接
MVC提供一些帮助函数创建链接,这些函数根据路径映射表自动调整生成的URL:
说明 | 示例 | 输出结果 |
应用程序相对URL | Url.Content("~/Content/Site.css") | /Content/Site.css |
到控制器action的链接 | Html.ActionLink("My Link", "Index", "Home") | <a href="/">My Link</a> |
Action的URL | Url.Action("GetPeople", "People") | /People/GetPeople |
使用路径映射的URL | Url.RouteUrl(new {controller = "People", action="GetPeople"}) | /People/GetPeople |
使用路径映射的链接 |
Html.RouteLink("My Link", new {controller = "People", action="GetPeople"}) |
<a href="/People/GetPeople">My Link</a> |
命名路径映射的链接 |
Html.RouteLink("My Link", "FormRoute", new {controller = "People", action="GetPeople"}) |
<a href="/app/forms/People/GetPeople">My Link</a> |
使用MVC Unobtrusive Ajax
MVC内建基于jQuery的unobtrusive Ajax的支持,之所以称之为unobtrusive Ajax是因为不像常规Ajax那样大量使用XML。要使用unobtrusive Ajax,首先需要在web.config的 configuration/appSettings一节开启UnobtrusiveJavaScriptEnabled支持:
...
<configuration>
<!-- other elements omitted for brevity -->
<appSettings>
<add key="webpages:Version" value="2.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="PreserveLoginUrl" value="true" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
<!-- other elements omitted for brevity -->
</configuration>
...
同时我们需要引用相关的javascript文件,可以把对这些脚本文件的引用放到布局文件_layout.cshtml中:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>@ViewBag.Title</title>
<link href="~/Content/Site.css" rel="stylesheet"/>
<script src="~/Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.min.js" type="text/javascript"></script>
</head>
<body>
@RenderBody()
</body>
</html>
jquery-1.7.1.min.js为jQuery的核心库,jquery.unobtrusive-ajax.min.js则提供Ajax功能(基于jquery库),文件名中的.min表示几乎不可能调试的缩减版本,可以在开发时使用非.min版本,发布时再采用.min版本。
使用Unobtrusive Ajax表单
下面以实例演示如何使用Ajax表单,从控制器开始:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using HelperMethods.Models;
namespace HelperMethods.Controllers
{
public class PeopleController : Controller
{
private Person[] personData = {
new Person {FirstName = "Adam", LastName = "Freeman", Role = Role.Admin},
new Person {FirstName = "Steven", LastName = "Sanderson", Role = Role.Admin},
new Person {FirstName = "Jacqui", LastName = "Griffyth", Role = Role.User},
new Person {FirstName = "John", LastName = "Smith", Role = Role.User},
new Person {FirstName = "Anne", LastName = "Jones", Role = Role.Guest}
};
public ActionResult Index()
{
return View();
}
public PartialViewResult GetPeopleData(string selectedRole = "All")
{
IEnumerable<Person> data = personData;
if (selectedRole != "All")
{
Role selected = (Role)Enum.Parse(typeof(Role), selectedRole);
data = personData.Where(p => p.Role == selected);
}
return PartialView(data);
}
public ActionResult GetPeople(string selectedRole = "All")
{
return View((object)selectedRole);
}
}
}
GetPeopleData()方法根据选择的角色过滤Person列表,返回一个分部视图,对应的GetPeopleData.cshtml:
@using HelperMethods.Models
@model IEnumerable<Person> @foreach (Person p in Model) {
<tr>
<td>@p.FirstName</td>
<td>@p.LastName</td>
<td>@p.Role</td>
</tr>
}
在Getpeople视图中我们调用GetPeopleData()同时创建一个Ajax form:
@using HelperMethods.Models
@model string
@{
ViewBag.Title = "GetPeople";
AjaxOptions 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("GetPeopleData", new { selectedRole = Model })
</tbody>
</table>
@using (Ajax.BeginForm("GetPeopleData", ajaxOpts))
{
<div>
@Html.DropDownList("selectedRole", new SelectList(new[] { "All" }.Concat(Enum.GetNames(typeof(Role)))))
<button type="submit">Submit</button>
</div>
}
Ajax.BeginForm()创建一个Ajax form,使用AjaxOptions对象作为参数,生成的HTML结果:
...
<form action="/People/GetPeopleData" data-ajax="true" data-ajax-mode="replace" data-ajax-update="#tableBody"id="form0" method="post">
...
浏览器请求GetPeople页面时jquery.unobtrusive-ajax.js扫描data-ajax=true的单元,以此确认这是一个ajax的表单,点击提交时不刷新整个页面,而是用从/people/getpeopledata返回的结果替换tablebody的内容。
Ajax options
AjaxOptions控制向服务器异步请求时的方式,包含这些属性:
属性 | 说明 |
Confirm | 在开始异步请求时向用户显示一条消息以确认 |
HttpMethod | 设置请求的HTTP方法,必须是get或者post |
InsertionMode | 如何嵌入服务器结果返回的HTML,可以是InsertAfter、InsertBefore、Replace(默认) |
LoadingElementId | 指定Ajax请求时要显示的Loading单元元素ID |
LoadingElementDuration | Loading元素动画显示的时长 |
UpdateTargetId | 请求返回结果要插入的元素ID |
Url | Ajax表单提交的URL |
上面的GetPeople视图Ajax form提交的URL是/People/GetPeopleData,如果用户禁止了java脚本,提交form返回的结果会只是GetPeopleData分部视图,我们可以直接在ajaxOptions指定ajax请求的URL来解决:
@using HelperMethods.Models
@model string
@{
ViewBag.Title = "GetPeople";
AjaxOptions ajaxOpts = new AjaxOptions
{
UpdateTargetId = "tableBody",
Url = Url.Action("GetPeopleData"),
LoadingElementId = "loading",
LoadingElementDuration = 1000,
Confirm = "Do you wish to request new data?"
};
}
<h2>Get People</h2>
<div id="loading" class="load" style="display:none">
<p>Loading Data...</p>
</div>
<table>
<thead><tr><th>First</th><th>Last</th><th>Role</th></tr></thead>
<tbody id="tableBody">
@Html.Action("GetPeopleData", new { selectedRole = Model })
</tbody>
</table>
@using (Ajax.BeginForm(ajaxOpts))
{
<div>
@Html.DropDownList("selectedRole", new SelectList(
new[] { "All" }.Concat(Enum.GetNames(typeof(Role)))))
<button type="submit">Submit</button>
</div>
}
生成的表单HTML:
...
<form action="/People/GetPeople"data-ajax="true" data-ajax-mode="replace" data-ajax-update="#tableBody" data-ajax-url="/People/GetPeopleData"id="form0" method="post">
...
这样表单提交的URL依然是/People/GetPeople,即使禁止了java脚本返回的仍然是GetPeople页面,ajax请求的URL通过data-ajax-url指定为/People/GetPeopleData。我们还设置 AjaxOptions.LoadingElementId为Loading,这是一个diplay:none风格的DIV元素,它只在AJAX异步请求时显示一秒钟(LoadingElementDuration = 1000)。AjaxOptions.Confirm= "Do you wish to request new data?" ,在每次Ajax请求时都会弹出网页Message对话框询问(对话框消息为这里设定的"Do you wish to request new data?")。
Ajax链接
上面的例子中我们使用表单提交数据,如果是使用链接做ajax异步请求可以这样操作:
...
<div>
@foreach (string role in Enum.GetNames(typeof(Role))) {
<div class="ajaxLink">
@Ajax.ActionLink(role, "GetPeopleData",
new {selectedRole = role},
new AjaxOptions {UpdateTargetId = "tableBody"})
</div>
}
</div>
...
这里对role枚举中每个元素生成一个链接,生成的链接元素类似:
...
<a data-ajax="true" data-ajax-mode="replace" data-ajax-update="#tableBody" href="/People/GetPeopleData?selectedRole=Guest">Guest</a>
...
点击某个链接时ajax返回的HTML数据会用于替换tableBody元素,和使用表单提交ajax请求效果一样。同样如果禁用了java脚本,返回的结果会只是getpeopledata分部视图,我们可以这样改进:
<div>
@foreach (string role in Enum.GetNames(typeof(Role))) {
<div class="ajaxLink">
@Ajax.ActionLink(role, "GetPeople",
new {selectedRole = role},
new AjaxOptions { UpdateTargetId = "tableBody", Url = Url.Action("GetPeopleData", new {selectedRole = role})
})
</div>
}
</div>
链接请求的地址是GetPeople,Ajax请求的URL则仅是GetPeopleData,请求的HTML结果作用于tablebody。
Ajax回调
AjaxOptions类暴露一组属性允许我们指定一个java脚本函数,在ajax请求周期中调用这些脚本函数:
属性 | jQuery事件 | 说明 |
OnBegin | beforeSend | 在Ajax请求发送前调用 |
OnComplete | complete | 请求成功时调用 |
OnFailure | error | 请求失败时调用 |
OnSuccess | success | 无论请求成功与否都在请求完成时调用 |
结合回调函数我们可以对上面的例子进一步修改,首先修改控制器的GetPeopleData方法:
public ActionResult GetPeopleData(string selectedRole = "All")
{
IEnumerable<Person> data = personData;
if (selectedRole != "All")
{
Role selected = (Role)Enum.Parse(typeof(Role), selectedRole);
data = personData.Where(p => p.Role == selected);
}
if (Request.IsAjaxRequest())
{
var formattedData = data.Select(p => new
{
FirstName = p.FirstName,
LastName = p.LastName,
Role = Enum.GetName(typeof(Role), p.Role)
});
return Json(formattedData, JsonRequestBehavior.AllowGet);
}
else
{
return PartialView(data);
}
}
我们使用Request.IsAjaxRequest判断请求是否来自于ajax,它的依据是浏览器在ajax请求时在头中会包含X-Requested-With=XMLHttpRequest。如果请求来自于ajax,控制器方法返回的是Json(data, JsonRequestBehavior.AllowGet)创建的JsonResult对象,默认JSON数据只在POST请求中发送,这里在第二个参数中指定JsonRequestBehavior.AllowGet允许在GET请求中使用JSON数据。MVC框架负责对formattedData做json封装,封装的格式由MVC尝试使用最适宜的方法确定,这里返回的JSON数据类似:
...
{"PersonId":0,"FirstName":"Adam","LastName":"Freeman",
"BirthDate":"\/Date(62135596800000)\/","HomeAddress":null,"IsApproved":false,"Role":0}
...
视图中我们在AjaxOptions的OnSucess回调函数中处理返回的JSON数据:
@using HelperMethods.Models
@model string
@{
ViewBag.Title = "GetPeople";
AjaxOptions ajaxOpts = new AjaxOptions
{
//UpdateTargetId = "tableBody",
Url = Url.Action("GetPeopleData"),
LoadingElementId = "loading",
LoadingElementDuration = 1000,
OnSuccess = "processData"
};
}
<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 People</h2>
<div id="loading" class="load" style="display: none">
<p>Loading Data...</p>
</div>
<table>
<thead>
<tr>
<th>First</th>
<th>Last</th>
<th>Role</th>
</tr>
</thead>
<tbody id="tableBody">
@Html.Action("GetPeopleData", new { selectedRole = Model })
</tbody>
</table>
@using (Ajax.BeginForm(ajaxOpts))
{
<div>
@Html.DropDownList("selectedRole", new SelectList(
new[] { "All" }.Concat(Enum.GetNames(typeof(Role)))))
<button type="submit">Submit</button>
</div>
} <div>
@foreach (string role in Enum.GetNames(typeof(Role)))
{
<div class="ajaxLink">
@Ajax.ActionLink(role, "GetPeople",
new { selectedRole = role },
new AjaxOptions
{
Url = Url.Action("GetPeopleData", new { selectedRole = role }),
OnSuccess = "processData"
})
</div>
}
</div>
脚本函数processData在AjaxOptions的OnSuccess回调时调用,它负责处理请求返回的JSON数据,从中分拆出各个Person对象,根据这些数据直接改写tableBody标签的内容,因此我们不再需要在AjaxOptions通过UpdateTargetId指定要替换内容的元素。
以上为对《Apress Pro ASP.NET MVC 4》第四版相关内容的总结,不详之处参见原版 http://www.apress.com/9781430242369。
ASP.NET MVC 4 (八) URL链接和Ajax帮助函数的更多相关文章
- 在ASP.NET MVC控制器中获取链接中的路由数据
在ASP.NET MVC中,在链接中附加路由数据有2种方式.一种是把路由数据放在匿名对象中传递: <a href="@Url.Action("GetRouteData&quo ...
- 返璞归真 asp.net mvc (5) - Action Filter, UpdateModel, ModelBinder, Ajax, Unit Test
原文:返璞归真 asp.net mvc (5) - Action Filter, UpdateModel, ModelBinder, Ajax, Unit Test [索引页] [源码下载] 返璞归真 ...
- 玩转Asp.net MVC 的八个扩展点
MVC模型以低耦合.可重用.可维护性高等众多优点已逐渐代替了WebForm模型.能够灵活使用MVC提供的扩展点可以达到事半功倍的效果,另一方面Asp.net MVC优秀的设计和高质量的代码也值得我们去 ...
- Asp.net MVC 的八个扩展点
http://www.cnblogs.com/richieyang/p/5180939.html MVC模型以低耦合.可重用.可维护性高等众多优点已逐渐代替了WebForm模型.能够灵活使用MVC提供 ...
- 【ASP.NET MVC 牛刀小试】 URL Route
例子引入 先看看如下例子,你能完全明白吗? using System; using System.Collections.Generic; using System.Linq; using Syste ...
- 白话ASP.NET MVC之一:Url 路由
好久没有写关于ASP.NET MVC的东西了,虽然<ASP.NET MVC4框架揭秘>已经完完整整的看完一遍,但是感觉和一锅粥差不多,没什么可写的,因为我自己不理解,也就写不出来.现在开始 ...
- Asp.Net MVC路由生成URL过程
这次谈一谈Asp.Net MVC中所学到的路由生成URL的相关技术,顺便提一提遇到的一些坑,真的是掉坑掉多了,也就习以为常了,大不了从坑里再爬出来.初学者,包括我,都以为,mvc的核心是模型视图控制器 ...
- 转:在ASP.NET MVC中通过URL路由实现对多语言的支持
对于一个需要支持多语言的Web应用,一个很常见的使用方式就是通过请求地址来控制界面呈现所基于的语言文化,比如我们在表示请求地址的URL中将上语言文化代码(比如en或者en-US)来指导服务器应该采用怎 ...
- ASP.NET MVC教程八:_ViewStart.cshtml
一.引言 _ViewStart.cshtml是在ASP.NET MVC 3.0及更高版本以后出现的,用Razor模板引擎新建项目后,Views目录下面会出现一个这样的文件: 打开_ViewStart. ...
随机推荐
- mongodb.mongoose维护内嵌数组元素
运行环境: - Nodejs - MongoDB 文档实例名: ProjectJob 文档格式如下: { "_id" : ObjectId("5bc69eb0b298b3 ...
- 了解 JavaScript (3)- 马上开始
之前演示了一个 Hello World 程序,而后讲解了一些基础概念,下面开始一些基础工作. 将脚本放在哪里 脚本可以放置在两个位置 <head></head>之间,头脚本(h ...
- postgresql 窗口函数排序实例
经常遇到一种应用场景,将部分行的内容进行汇总.比较.排序. 比如数据表名称test.test2 select num,province from test.test2 得到结果: ;"黑龙江 ...
- shell while内获取外部变量内容
一.问题 问题很简单,看下面一段tmp.sh代码: #!/bin/sh x="this is the initial value of x" cat /tmp/tmp | whil ...
- js 模拟call、apply、bind实现
1.模拟call实现 Function.prototype.myCall = function (context) { var context = context || window // 给 con ...
- 关于FMDatabase executeQuery的问题
如果你碰到这个问题,请查看idx的值,并查看SQL语句中第6个字段的值有问题(从0开始),比如你给的值是NSInteger会报错,需要将其转成NSString.
- ROS actionlib学习(二)
在ROS actionlib学习(一)中的例子展示了actionlib最基本的用法,下面我们看一个稍微实际一点的例子,用actionlib计算斐波那契数列,并发布反馈(feedback)和结果(res ...
- Swap 分区的2种方式 详解与例子
安装完Linux系统后,swap分区太小怎么办,怎么可以扩大Swap分区呢?有两个办法,一个是从新建立swap分区,一个是增加swap分区.下面介绍这两种方法: 第一您必须有root权限,过程中一定要 ...
- Android--保持加速度传感器在屏幕关闭后运行(收集)
由于写论文需要,需要用手机加速度采集数据,关于android加速度传感器的介绍网上一抓一大把,但大多都是大同小异,跟官网文档差不多.自己写了个取加速度传感器的APK,发现数据有点不对劲,原理屏幕一关后 ...
- oracle本地编译问题
oracle10.2: --将过程重新编译为本地编译方式,提示有编译错误,经查提示未设置plsql_native_library_dir 参数 SQL> alter procedure p_xx ...