Unobtrusive Ajax

Ajax (Asynchronous JavaScript and XML 的缩写),如我们所见,这个概念的重点已经不再是XML部分,而是 Asynchronous 部分,它是在后台从服务器请求数据的一种模型。MVC 框架内置了对 Unobtrusive Ajax 的支持,它允许我们通过 MVC 的 Help mothod 来定义 Ajax 的特性,而不用在 View 中参杂一大段 JavaScript 代码。

本文目录:

普通 Ajax 使用方式

在讲 MVC 中的 Unobtrusive Ajax 之前,我们先来看看 MVC 中 Ajax 的普通使用方式,读者可以在阅读后文的时候进行比较学习。
新建一个MVC应用程序(基本模板),添加一个名为 Home 的 controller,为自动生成的 Index action 添加视图,编辑 Index.cshtml 代码如下:

@{
ViewBag.Title = "Index";
} <script type="text/javascript">
function test() {
$.ajax({
url: '@Url.Action("GetTestData")',
type: "POST",
success: function (result) {
$("#lblMsg").text(result.msg);
}
});
}
</script> <h2 id="lblMsg"></h2>
<input type="button" value="测试" onclick="test();" />

在 HomeController 中添加一个名为 Test 的 action,如下:

public JsonResult GetTestData() {
return Json(
new { msg = "Datetime from server:" + DateTime.Now.ToString("HH:mm:ss") }
);
}

运行程序,点击测试按钮,我们可以看到用 Ajax 从后台取回来的时间:

每次点击测试按钮时间都会刷新。这个地方有一点需要提醒大家,这个例子中 $.ajax() 方法使用的是 POST 请求,如果要使用 GET 请求,Test action 中调用 Json 方法需要设置 JsonRequestBehavior 的值为 AllowGet(默认是 DenyGet),如下:

public JsonResult GetTestData() {
return Json(
new { msg = "Datetime from server:" + DateTime.Now.ToString("HH:mm:ss") },
JsonRequestBehavior.AllowGet
);
}

另外,改成 GET 请求后,多次点击测试按钮,时间不会刷新。这是因为 GET 请求在 ASP.NET 中对于相同的URL请求返回的是缓存中的数据。

什么是 Unobtrusive Ajax

Unobtrusive Ajax 是在 Web 页面使用 JavaScript 的一种通用方式。这个术语没有明确的定义,但它有如下基本的原则(来自维基百科):

  • 行为(JavaScript 代码)与 Web 页面的结构(Html 标记)和表现(CSS样式)分离。
  • JavaScript 最佳实现,解决JavaScript语言本身存在的传统问题(如缺乏可扩展性和开发人员编码风格不一致性)。
  • 解决浏览器兼容性问题。

为了加深理解,请观察如下某个 Unobtrusive Ajax 的“结构”部分的一段代码:

...
<form action="/People/GetPeopleData" data-ajax="true" data-ajax-mode="replace" data-ajax-update="#tableBody" id="form0" method="post">
...

这是 MVC 开启 Unobtrusive JavaScript 后调用 Ajax.BeginForm 方法生成的代码。这段代码和 JavaScript 是完全分离的,Html标签通过一些标记来告诉 JavaScript 所具有什么样的行为。分离出来的 JavaScript 文件(MVC中指引入的jquery.unobtrusive-ajax.min.js文件)中的代码,没有一句是专门为某个特定的Web页面中的某个Html元素来编写的,即所有函数都是通用的。这就是 Unobtrusive Ajax 的核心思想。

相对于普通使用 Ajax 的方式,Unobtrusive Ajax 更容易阅读,增强了可扩展性和一致性,而且方便维护。

使用 MVC Unobtrusive Ajax

在 MVC 中使用 Unobtrusive Ajax ,首先要将其“开启”,需要做两个动作。一个是配置根目录下的 Web.config 文件,在 configuration/appSettings 节点下的 UnobtrusiveJavaScriptEnabled 值设为 true,如下所示:

...
<configuration>
<appSettings>
...
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
</configuration>
...

UnobtrusiveJavaScriptEnabled 的值在程序创建的时候默认为true,在开发的时候有时候只需要检查一下。第二个动作就是在需要使用 MVC Unobtrusive Ajax 的 View 中引入jquery库和jquery.unobtrusive-ajax.min.js文件,一般更为常见的是在 /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>

现在我们来做一个使用 Unobtrusive Ajax 的例子,从服务器获取一个简单的用户列表。为此我们需要准备一个Model,如下:

namespace MvcApplication1.Models {
public class Person {
public string ID { get; set; }
public string Name { get; set; }
public Role Role { get; set; }
} public enum Role {
Admin, User, Guest
}
}

我一般习惯先写后台方法,再写UI。创建一个名为 People 的 controller, 在该 controller 中写好要用的 action,代码如下:

public class PeopleController : Controller {
public class PeopleController : Controller {
private Person[] personData = {
new Person {ID = "ZhangSan", Name = "张三", Role = Role.Admin},
new Person {ID = "LiSi", Name = "李四", Role = Role.User},
new Person {ID = "WangWu", Name = "王五", Role = Role.User},
new Person {ID = "MaLiu", Name = "马六", 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 action方法,根据 selectedRole 获取用户数据并传递给 PartialView 方法。

接着为 GetPeopleData action 创建一个partial view:/Views/People/GetPeopleData.cshtml ,代码如下:

@using MvcApplication1.Models
@model IEnumerable<Person> @foreach (Person p in Model) {
<tr>
<td>@p.ID</td>
<td>@p.Name</td>
<td>@p.Role</td>
</tr>
}

再创建我们的主视图 /Views/People/GetPeople.cshtml,代码如下:

@using MvcApplication1.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>
}

先是创建了一个 AjaxOptions 对象,通过它的一些属性(如UpdateTargetId、Url、HttpMethod等)可设置 Ajax 如何请求。这些属性可见名思意,如 UpdateTargetId 表示调用 Ajax 请求后要刷新的元素(通过元素ID来指定)。然后把需要提交到服务器的表单包括在 Ajax.BeginForm() 方法内,通过 submit 元素将该表单数据提交到服务器。

为了运行效果美观些,我们在 _Layout.cshtml 文件中为 table 元素添加一些样式,如下:

...
table, td, th {
border: thin solid black; border-collapse: collapse; padding: 5px;
background-color: lemonchiffon; text-align: left; margin: 10px 0;
}
...

运行程序,URL 定位到 /People/GetPeople,在页面中点击提交按钮,效果如下:

 

Ajax.BeginForm 是通过提交表单的方式向服务器发送 ajax 请求,MVC中也可以使用 Ajax.ActionLink() 方法生成链接来向服务器发送 ajax 请求。下面我们在 GetPeople.cshtml 视图中增加这种请求方式:

<div>
@foreach (string role in Enum.GetNames(typeof(Role))) {
@Ajax.ActionLink(role, "GetPeopleData", new {selectedRole = role},
new AjaxOptions {UpdateTargetId = "tableBody"}) @:&nbsp;

}
</div>

效果和前面是一样的:

Ajax.ActionLink() 和 Ajax.BeginForm() 不同的是,前者只能通过 Url 参数向服务器传送数据。

Unobtrusive Ajax 如何工作

Unobtrusive Ajax 是如何工作的呢?

当调用 Ajax.BeginForm 方法后,通过 AjaxOptions 对象设置的属性将会被转化成 form 元素的属性(标记),这些属性以 data-ajax 开头,如本示例生成的 form 元素:

<form action="/People/GetPeopleData" data-ajax="true" data-ajax-mode="replace" data-ajax-update="#tableBody" id="form0" method="post">
...

当 GetPeople.cshtml 视图加载完成并呈现 Html 页面时,jquery.unobtrusive-ajax.js 库寻找所有 data-ajax 属性值为true的元素,然后根据其他以 data-ajax 开头的属性值,jQuery 库中的函数将知道如何去执行 Ajax 请求。

配置 AjaxOptions

AjaxOptions 类中的属性告诉 MVC 框架如何生成 Ajax 请求相关的 JavaScript 和 Html 代码。它包含如下属性:

这些属性 VS 的智能提示都有很好的解释,这里不一个一个讲,只选几个有代表性的讲讲。

AjaxOptions.Url 属性

在上面的示例中,我们在 Ajax.BeginForm() 方中指定了 action 名称参数,MVC 帮我们生成了Ajax请求的Url ( action="/People/GetPeopleData" )。这样做存在一个问题,当浏览器禁用JavaScript的时候,点击提交按钮页面将发生新的请求(非Ajax请求 /People/GetPeopleData),这样服务器返回的数据将直接替换掉原来的页面。解决这个问题可以使用 AjaxOptions.Url 属性,原因是 AjaxOptions.Url 属性会生成另外一个专门用于 ajax 请求的Url。如下我们对 /Views/People/GetPeople.cshtml 进行简单的修改:

...
@{
ViewBag.Title = "GetPeople";
AjaxOptions ajaxOpts = new AjaxOptions {
UpdateTargetId = "tableBody",
Url = Url.Action("GetPeopleData")
};
}
...
@using (Ajax.BeginForm(ajaxOpts)) {
...
}

运行后我们看到的是和先前一样的结果,说明在效果上没有区别。但它生成的 form 属性却不一样:

<form id="form0" action="/People/GetPeople" method="post" data-ajax-url="/People/GetPeopleData" data-ajax-update="#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,服务器将返回原来整个的页面。虽然局部未能刷新,但不会让用户觉得网站做得很糟糕。

Ajax 加载数据的同时给用户反馈

当加载数据需要花较长时间,为了避免假死状态,应当给用户一个反馈信息,如“正在加载...”字样。在 MVC 的 Unobtrusive Ajax 中通过 AjaxOptions 的 LoadingElementId 和 LoadingElementDuration 两个属性可轻松做到这一点。修改 GetPeople.cshtml 如下:

@using MvcApplication1.Models
@model string @{
ViewBag.Title = "GetPeople";
AjaxOptions ajaxOpts = new AjaxOptions {
UpdateTargetId = "tableBody",
Url = Url.Action("GetPeopleData"),
LoadingElementId = "loading",
LoadingElementDuration = 1000,

};
}
<h2>Get People</h2>
<div id="loading" class="load" style="display:none">
<p>Loading Data...</p>
</div>
...

不解释,运行程序看效果:

弹出确认对话框

使用MVC中的 Unobtrusive Ajax 弹出确认对话框也很方便,设置一下 AjaxOptions.Confirm 属性的值却可,如下:

...
@{
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?"
};
}
...

弹出的对话框如下:

Ajax 回调函数

AjaxOptions 类中的 OnBegin、OnComplete、OnFailure 和 OnSuccess 属性允许我们在 ajax 请求周期的某个状态点定义回调函数。来看具体的用法。

在 GetPeople.cshtml 文件中加入如下4个回调函数:

<script type="text/javascript">
function OnBegin() {
alert("This is the OnBegin Callback");
}
function OnSuccess(data) {
alert("This is the OnSuccessCallback: " + data);
}
function OnFailure(request, error) {
alert("This is the OnFailure Callback:" + error);
}
function OnComplete(request, status) {
alert("This is the OnComplete Callback: " + status);
}
</script>

接着设置 AjaxOptions 对象的4个事件属性:

...
@{
ViewBag.Title = "GetPeople";
AjaxOptions ajaxOpts = new AjaxOptions {
UpdateTargetId = "tableBody",
Url = Url.Action("GetPeopleData"),
OnBegin = "OnBegin",
OnFailure = "OnFailure",
OnSuccess = "OnSuccess",
OnComplete = "OnComplete"

};
}
...

运行程序,弹出三个消息框如下:

  

这四个事件属性中最常用的就是 OnSuccess 和 OnFailure 两个属性了,如我们会经常在 OnSuccess 回调函数中对返回的 Json 数据进行处理。


其实我个人更倾向于普通的 Ajax 使用方式。Ajax.BeginForm() 和 Ajax.ActionLink() 用的少,习惯用 Html.BeginForm() 或 Html.ActionLink() 和手写 jQuery ajax 代码来代替。

参考:《Pro ASP.NET MVC 4 4th Edition》

作者:Liam Wang

mvc验证jquery.unobtrusive-ajax的更多相关文章

  1. MVC之Ajax.BeginForm使用详解之更新列表 mvc验证jquery.unobtrusive-ajax

    MVC之Ajax.BeginForm使用详解之更新列表   1.首先,请在配置文件设置如下:(该项默认都存在且为true) <add key="UnobtrusiveJavaScrip ...

  2. ASP.NET Core中的jQuery Unobtrusive Ajax帮助器

    最近在ASP.NET Core下写文章管理系统时,准备在分页显示文章内容时,使用Ajax.网上找了篇帖文,简单翻一下,仅供自己查阅. 原链接:https://dotnetthoughts.net/jq ...

  3. AjaxHelper创建的ajax无效,JQuery直接方法post有效,原来是Microsoft.jQuery.Unobtrusive.Ajax错误,NuGet解决

    Get-Package -ListAvailable -Filter Microsoft.JQuery Microsoft.jQuery.Unobtrusive.Ajax –Version 3.2.0

  4. ASP.NET MVC验证 - jQuery异步验证

    本文主要体验通过jQuery异步验证. 在很多的教材和案例中,MVC验证都是通过提交表单进行的.通过提交表单,可以很容易获得验证出错信息.因为,无论是客户端验证还是服务端验证,总能找到与Model属性 ...

  5. MVC 使用Jquery实现AJax

    View <script type="text/javascript"> function GetTime() { $.get("Home/GetTime&q ...

  6. [ASP.NET MVC 小牛之路]14 - Unobtrusive Ajax

    Ajax (Asynchronous JavaScript and XML 的缩写),如我们所见,这个概念的重点已经不再是XML部分,而是 Asynchronous 部分,它是在后台从服务器请求数据的 ...

  7. 【ASP.NET MVC 学习笔记】- 15 Unobtrusive Ajax

    本文参考:http://www.cnblogs.com/willick/p/3418517.html 1.Unobtrusive Ajax允许我们通过 MVC 的 Help mothod 来定义 Aj ...

  8. 【转】Unobtrusive Ajax的使用

    [转]Unobtrusive Ajax的使用 Ajax (Asynchronous JavaScript and XML 的缩写),如我们所见,这个概念的重点已经不再是XML部分,而是 Asynchr ...

  9. MVC自定义验证 jquery.validate.unobtrusive

    MVC的验证 jquery.validate.unobtrusive 阅读目录 一.应用 二.验证规则 1.一.简单规则 2.二.复杂一点的规则 3.三.再复杂一点的规则(正则) 4.四.再再复杂一点 ...

随机推荐

  1. iOS7 文本转语音 AVSpeechSynthesizer

    OS7 的这个功能确实不错.我刚试了下,用官方提供的API ,简单的几句代码就能实现文本转语音! Xcode 5.0 工程建好后首先把AVFoundation.framework 加入到工程 AVSp ...

  2. WPF换肤之二:可拉动的窗体

    原文:WPF换肤之二:可拉动的窗体 让我们接着上一章: WPF换肤之一:创建圆角窗体 来继续. 在这一章,我主要是实现对圆角窗体的拖动,改变大小功能. 拖动自绘窗体的步骤 首先,通过上节的设计,我们知 ...

  3. CMD经常使用的命令

    Win7Excuting订单 win+R.运行该快捷方式.下面3一个人必须知道: ping 它是用来检查网络是否通畅或者网络连接速度的命令. 作为一个生活在网络上的管理员或者黑客来说,ping命令是第 ...

  4. 利用jsoup爬取百度网盘资源分享连接(多线程)

    突然有一天就想说能不能用某种方法把百度网盘上分享的资源连接抓取下来,于是就动手了.知乎上有人说过最好的方法就是http://pan.baidu.com/wap抓取,一看果然链接后面的uk值是一串数字, ...

  5. Form表单中的action路径问题

    今天刚接触web,在用jsp和servlet做一个简单的登陆的时候在Form表单action属性和method属性的一些问题:  我遇到的是Form表单提交到servelet处理时遇到的问题:  (1 ...

  6. linux下Ftp环境的搭建

      Ftp环境的搭建 1.ftp软件的安装 使用ssh远程连接linux系统,上传和下载一些文件,Ftp是不可少的 Ftp的安装很简单,远程登录系统后使用命令 yum list vsftpd 通过提示 ...

  7. [Django](1093, &quot;You can&#39;t specify target table &#39;fee_details_invoices&#39; for update in FROM clause&quot;) 错误

    dele_id = Fee_details_invoices.objects.filter(fee_detail_id__in=fee_id_list, return_type='2').values ...

  8. Android实战技术:IPC方式简介教程

    非实时,通知性的方式 第一种方式就是Intent,Intent可以非常方便的通讯,但是它是非实时的,无法进行实时的像函数调用那样的实时的通讯. 实时的函数调用 但是IPC的根本目的还是为了实现函数的调 ...

  9. 完全合并C++面试题

    C++面试题 1.是不是父母写了virtual 功能,假设子类重写它的功能不virtual ,也使多态性? virtual修饰符隐形遗传. private 还集成.问权限而已 virtual可加可不加 ...

  10. EasyUI基础searchbox&amp;progressbar(搜索框,进度条)

    easyui学习的基本组成部分(八个部分)硕果仅存searchbox和pargressbar.tooltip该,有一点兴奋.本文将偏向searchbox和pargressbar做一个探讨.鉴于双方的内 ...