ASP.NET MVC5高级编程 之 Ajax
jQuery不仅支持所有现代浏览器,包括IE、Firefox、Safari、Opera和Chrome等,还可以在编写代码和浏览器API冲突时隐藏不一致性(和错误)。
1. jQuery
jQuery擅长在HTML文档中查找、遍历和操纵HTML元素。一旦找到元素,jQuery就可以方便的在其上进行操作,如连接事件处理程序、使其具有动画效果以及围绕它的Ajax交互等。
1.1 jQuery函数
jQuery函数对象可以用来访问jQuery特性。
$(function (){ $("#album-list img").mouseover(function(){ $(this).animate({ height: '+=25', width: '+=25'}) .animate({ height: '-=25', width: '-=25'}); }); });
- 第一行代码调用了jQuery函数($),并向其中传递了一个匿名的JavaScript函数作为第一个参数:
$(function (){
当传递一个函数作为第一个参数时,jQuery就会假定这个函数是要在浏览器完成构建(由服务器提供的)HTML页面中的文档对象模型(Document Object Model, DOM)后立即执行,换句话说,这个函数在从服务器端加载完HTML页面之后执行。这样就可以安全的执行函数中与DOM冲突的脚本,这种情况称为“DOM准备”事件。
- 第二行代码向jQuery函数传递一个字符串“#album-list img”:
$("#album-list img").mouseover(function(){
jQuery把这个字符串解释为选择器。选择器会告知jQuery需要在DOM中查找的元素。我们可以使用像类名和相对位置这样的特性值来查找元素。这一行代码的意图是告知jQuery查找id值为“album-list”的元素中的所有图像。
当执行选择器时,它会返回一个包含零个或多个匹配元素的封装集(wrapped set)。我们可以调用其他任何jQuery方法来操作封装集中的元素。例如,上面的代码调用mouseover方法为与选择器匹配的每个图像元素的onmouseover事件连接处理程序。
- jQuery利用JavaScript的函数式编程特性,经常把创建的或传递的函数作为jQuery方法的参数。为了表达事件触发时想进行的处理,就向mouseover方法传递了一个包含事件处理代码的函数参数:
$(this).animate({ height: '+=25', width: '+=25'}) .animate({ height: '-=25', width: '-=25'});
上面的例子实现了在触发mouseover事件时,匹配选择器的img元素会产生动画效果。在上面的代码中,之所以使用this关键字来引用要做动画效果的元素,是因为this是指向的是触发事件的元素。
注意代码第一次将元素传递给jQuery函数的方法($(this))。jQuery将该参数看成一个元素的引用参数,并返回一个包含有该元素的封装集。
一旦将某个元素包含在jQuery封装集中,就可以调用jQuery方法(如animate)来操纵这个元素。示例中的代码首先将图像放大,然后在缩小的效果。
1.2 jQuery选择器
选择器是指传递给jQuery函数的,用来在DOM中选择元素的字符串。
例子 | 意义 |
$("#header") | 查找id值为“header”的元素 |
$(".editor-label") | 查找class名为“.editor-label的所有元素” |
$("div") | 查找所有<div>元素 |
$("#header div") | 查找id值为“header”元素的所有后代<div>元素 |
$("#header>div") | 查找id值为“header”元素的所有子<div>元素 |
$("a:even") | 查找编号为偶数的锚标签 |
“#album-list img”用来选择id为album-list的<img>标签。
作为选择器的字符串看起来像层叠样式表(Cascading Style Sheet,CSS)中的项,是因为jQuery选择器的语法派生自CSS3.0选择器的语法,并在其基础上做了一些补充。
1.3 jQuery事件
jQuery的另一个优势在于,它提供了用来订阅DOM中事件的API。尽管使用一个通用的on方法可以捕获指定名称的任何事件,但jQuery也为一般的事件提供了专门的方法,比如click、blur和submit。
可以通过传进一个函数来告知jQuery在事件触发时进行的处理。传递进的函数可以是匿名的,也可以是一个作为事件处理程序的命名函数,如下所示:
$("#album-list img").mouseover(function(){ animateElement($(this)); }); function animateElement(element){ element.animate({ height: '+=25', width: '+=25'}) .animate({ height: '-=25', width: '-=25'}); }); }
一旦选择了一些DOM元素或是在一个事件处理程序内,jQuery就可以很容易的操纵页面上的元素,读取或设置他们的特性值,添加或移除他们的CSS类等。下面的代码演示了当用户的鼠标移过元素时,如何向一个页面上的锚标签添加或从中删除highlight类。当用户在标签上移动鼠标时,锚标签就会改变外观(假如有一个合适的highlight样式设置):
$("a").mouseover(function(){ $(this).addClass("highlight"); }).mouseout(function(){ $(this).removeClass("highlight"); })
注意:
- 代码中用到的所有依赖于封装集的jQuery方法,像mouseover方法,都返回同样的jQuery封装集。这就是说可以继续在选择的元素上调用jQuery方法,而不用再重新选择这些元素。这称为方法链。
- 许多常用操作在jQuery中都有与其对应的捷径方法(shortcut)。设置mouseover和mouseout效果是一种常见的操作,切换样式类型也是一种常见的操作。可以使用jQuery捷径方法重写上面的代码:
$("a").hover(function(){ $(this).toggleClass("highlight"); })
jQuery包含了向Web服务器回发异步请求所需要的所有功能。可以利用jQuery来生成POST请求或GET请求,并且当请求完成(或出现错误)时jQuery会发出通知。
非侵入式JavaScript:
在Web早期阶段,jQuery出现以前,在同一个文件中混杂JavaScript代码和HTML标记是非常流行的做法。将JavaScript代码作为某个特性的值放入HTML元素中是很常见的,如以下代码:
<div onclick="javascript:alert('click');">Testing, testing</div>
当时在标记中嵌入JavaScript代码,是因为没有更简单的方法可以用来捕获单击事件,尽管嵌入的JavaScript代码可以实现事件捕获,但是这样的代码不够简洁。jQuery改变了这种情况,因为jQuery提供了查找元素和捕获单击事件更好的方法。现在可以从HTML特性中移除JavaScript代码了。事实上,可以将javascript代码与HTML完全分离。
非侵入式javascript很好的实践了javascript代码和标记的分离,可将所有需要的脚本代码打包到js文件中。如果查看视图的源代码,将不会看到有javascript代码嵌入在标记中。即使查看视图渲染的HTML标记,也看不到任何的javascript代码,脚本留下的唯一的痕迹是一个或多个引用javascript文件的<script>标签。
1.4 jQuery的用法
因为jQuery非常常用,站点布局(/Views/Shared/_Layout.cshtml)的footer部分包含了一个jQuery脚本引用。因此,默认情况下,站点的任何视图中都可以使用jQuery。在没有使用默认布局的任何视图中,或者如果我们在站点布局中删除了jQuery脚本引用,添加jQuery脚本引用和删除jQuery脚本引用是很容易的,只需要直接脚本引用或者使用预配置的jQuery捆绑。
要添加脚本引用,可包含如下的代码:
<script src="~Scripts/jquery-1.10.2.js"></script>
注意:ASP,NET MVC的Razor视图引擎会把这里的~操作符解析为当前网站的根目录,即便它出现了src特性。另外,HTML5不需要指定类型特性为text/javascript。
但这种方法依赖于版本,更好的在驶入中包含jQuery引用的方法是使用内置的、版本无关的jQuery脚本捆绑。
@Scripts.Render(~/bundles/jquery)
上面的调用将渲染/App_Start/BundleConfig.cs中预定义的“jquery”脚本捆绑,这种捆绑利用了ASP.NET中的捆绑和微小特性,该特性利用版本号中包含的通配符匹配,自动优先使用jQuery的轻量版本。
public static void RegisterBundles(BundleCollection bundles) { bundles.Add(new ScriptBundle("~/bundles/jquery").Include( "~/Scripts/jquery-{version}.js")); //...... }
2.1 自定义脚本
自定义的JavaScript代码,一般放置在“Scripts/App”目录下。
此处创建一个新的MusicScripts.js文件,并添加以下代码:
$(function () { $("#album-list img").mouseover(function () { $(this).animate({ height: '+=25', width: '+=25' }) .animate({ height: '-=25', width: '-=25' }); }); });
2.2 在节中放置脚本
@section Scripts{ <script src="~/Scripts/App/MusicScripts.js"></script> }
2.3 Scripts目录下的其他文件
- Bootstrap.js:
包含一组基于jQuery的插件,他们通过添加额外的交互行为来增强Bootstrap。例如,Modals插件可显示简单的、使用Bootstrap样式的模态化界面,他使用jQuuery管理事件和动态页面显示。
- Respond.js:
是一个很小的JavaScript库,包含的原因是因为Bootstrap要用到。
- Modernizr.js:
通过改造老版本浏览器来帮助我们构建富有现代气息的应用程序。其中一个重要工作就是在老版本浏览器中启动新的HTML5元素(比如header、nav和menu),也可以检测特定浏览器是否支持一些高级功能,像定位位置(geolocation)和绘画画布(drawing canvas)。
3 Ajax
3.1 Ajax辅助方法
ASP.NET MVC框架中包含一组Ajax辅助方法,他们可以用来创建表单和指向控制器操作的链接,但不同的是它们是异步进行的。当然使用这些辅助方法时,不需要编写任何脚本代码来实现程序的异步性。
这些Ajax辅助方法依赖于非侵入式MVC的jQuery扩展,如果使用这些辅助方法,需要引入脚本文件jquery.unobtrusive-ajax.js,并在视图中添加此脚本引用。
3.2 在项目中添加非侵入式Ajax脚本
Nuget --> Microsoft jQuery Unobtrusive Ajax --> 安装
脚本引用可以添加到程序的_Layout视图中,也可以仅添加到使用Ajax辅助方法的视图中。除非在网站中发出大量的Ajax请求,否则建议添加到单独的视图中。
脚本的添加可以拖拽。
3.3 Ajax的ActionLink方法
与HTML辅助方法类似,Ajax属性上的大部分Ajax辅助方法都是扩展方法(出了AjaxHelper类型之外)。
Ajax属性的ActionLink方法可创建一个具有异步行为的锚标签,代码实现:
1 <div id="dailydeal"> 2 @Ajax.ActionLink("Click here to see today's special!", 3 "DailyDeal", 4 null, 5 new AjaxOptions 6 { 7 UpdateTargetId = "dailydeal", 8 InsertionMode = InsertionMode.Replace, 9 HttpMethod = "GET" 10 }, 11 new {@class = "btn btn-primary"}) 12 </div>
ActionLink
- 第一个参数指定了链接文本;
- 第二个参数是要异步调用的操作的名称,类似于同名的HTML辅助方法,Ajax辅助方法ActionLink也提供了各种重载版本,用来传递控制器的名称、路由值和HTML特性。
- AjaxOptions参数指定了发送请求和处理服务器返回的结果的方式。参数中还包括用来处理错误、显示加载元素、显示确认对话框等的选项。
在这个示例中,AjaxOptions参数的选项指定了要使用来自服务器的响应元素来替换id值为“dailydeal”的元素
- 最后的htmlAttributes参数指定了为链接使用的HTML类,以应用一个基本的Bootstrap按钮样式。
为得到服务器的响应,需要在控制器的HomeController上添加一个DailyDeal操作:
public ActionResult DailyDeal() { var album = GetDailyDeal(); return PartialView("_DailyDeal",album); } private Album GetDailyDeal() { var album = storeDB.Albums .OrderBy(a => System.Guid.NewGuid()) .First(); album.Price *= 0.5m; return album; }
Html5特性
非侵入式JavaScript的显著特点是在HTML中不包含任何JavaScript代码,也就是在HTML中看不到脚本代码。Ajax代码中指定的所有设置被编码成了HTML元素的特性,并且大多数的编码特性都有data-前缀,通常称为data-特性。
HTML5规范为私有应用程序状态保留了data-特性。换句话说,Web浏览器不会尝试解释data-特性的内容。因此可放心的把数据交给它,这些数据不会影响页面的显示或渲染。
向应用程序中添加jquery.unobtrusive-ajax文件的目的是查找特定的data-特性,然后操纵元素使其表现出不同行为。如果知道使用jQuery可以很容易地查找元素,那么非侵入式JavaScript文件中出现如下所示的代码也就很容易理解了
$(function)(){ $("a[data-ajax]=true"). //do something });
这段代码将使用jQuery查找data-ajax特性值为true的所有锚元素。元素上的data-ajax特性用来标识该元素需要实现异步行为。一旦非侵入式脚本识别了异步元素,它就可以读取该元素的其他设置(像替换模式、更新目标以及HTTP方法),还可以通过使用jQuery连接事件和发送请求来修改该元素的行为。
所有ASP.NET MVC Ajax特性都使用data-特性。
3.4 Ajax表单
使用Ajax在页面上放置一个异步表单
1 <div class="panel panel-default"> 2 <div class="panel-heading">Artist search</div> 3 <div class="panel-body"> 4 @using (Ajax.BeginForm("ArtistSearch", "Home", 5 new AjaxOptions 6 { 7 InsertionMode = InsertionMode.Replace, 8 HttpMethod = "GET", 9 OnFailure = "searchFailed", 10 LoadingElementId = "ajax-loader", 11 UpdateTargetId = "searchresults", 12 })) 13 { 14 <input type="text" name="q" /> 15 <input type="submit" value="search" /> 16 <img id="ajax-loader" 17 src="@Url.Content("~/Images/ajax-loader.gif")" 18 style="display:none" /> 19 } 20 <div id="searchresults"></div> 21 </div> 22 </div>
- 当用户单击提交按钮时,浏览器就会向控制器HomeController的ArtistSearch操作发送异步的GET请求
- LoadingElementId作为其中的一个选项。当执行异步请求时,客户端框架会自动的显示这个元素。此处为一个等待的动画。
- OnFailure选项包括许多参数,可以设置这些参数以捕获来自Ajax请求的各种客户端事件,如OnBegin、OnComplete、OnSuccess和OnFailure等。可以给这些参数赋予一个JavaScript函数的名称,当事件触发时,调用该函数
上面的代码为OnFailure事件指定了一个名为searchFailed的函数,因此需要使用运行时能够访问到这个函数。此处将函数存放在MusicScript.js文件中。
function searchFailed() { $("#searchresults").html("Sorry, there was a problem with the search."); }
如果服务器返回一个错误,就意味着Ajax辅助方法执行失败,此时可以捕获OnFailure事件。
- 最后,当用户单击提交按钮提交表单时,服务器会收到一个Ajax请求,并可能以任意格式的内容做出响应。当客户端收到来自服务器端的响应时,非侵入式脚本就会将相应内容放入DOM中。
此处,新内容要替换的是一个id值为searchresults的元素。
控制器中的代码为:
public ActionResult ArtistSearch(string q) { var artists = GetArtists(q); return PartialView("_ArtistSearch", artists); } private List<Artist> GetArtists(string searchString) { return storeDB.Artists .Where(a => a.Name.Contains(searchString)) .ToList(); }
渲染的部分视图利用模型构建列表。该部分视图的名称是ArtistSearch.cshtml,位于项目的Views/Home文件夹下。
@model IEnumerable<MvcMusicStore.Models.Artist> <div id="searchresults"> <ul> @foreach (var item in Model) { <li>@item.Name</li> } </ul> </div>
4客户端验证
对于数据注解特性来说,ASP.NET MVC框架的客户端验证是默认开启的,下面介绍Album类的Title和Price属性:
[Required] [StringLength(, MinimumLength = )] public string Title { get; set; } [Required] [Range(0.01, 100.00)] [DataType(DataType.Currency)] public decimal Price { get; set; }
数据注解特性使得这两个属性值必须键入,并且还对Title属性值限定了长度,对Price属性值范围限定了范围。ASP.NET MVC的模型绑定器在设置这些属性时会执行服务器端验证。这些内置的特性也触发客户端验证。客户端验证依赖于jQuery验证插件。
4.1 jQuery验证
jQuery验证插件(jquery.validate)默认情况下在MVC5应用程序项目的Scripts文件夹下。如果想实现客户端验证,那么在相应的视图中就需要包含jqueryval捆绑的引用。如果引用放到_Layout中,所有的视图上都会加载脚本,而不是仅在需要jQuery验证的视图上加载脚本,性能会受到影响。
4.2 自定义验证
编写的MaxWordsAttribute验证特性代码如下:
public clsaa MaxWordsAttribute : ValidationAttribute { public MaxWordsAttribute(int maxWords) : base("{0} has too many words.") { _maxWords = maxWords; } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { var valueAsString = value.ToString(); if( valueAsString.Split(' ').Length > _maxWords) { var errorMessage = FormatErrorMessage(validationContext.DisplayName); return new ValidationResult(errorMessage); } return ValidationResult.Success; } private readonly int _maxWords; }
该特性只支持服务器端的验证,使用方法如下:
[MaxWords()] public string Title { get; set; }
4.2.1 IClientValidatable
IClientValidatable接口定义了单个方法:GetIClientValidationRules。当ASP.NET MVC框架使用这个接口查找验证对象时,它会调用GetClientValidationRules方法来检索ModelClientValidationRule对象序列。这些对象携带有框架发送给客户端的元数据和规则。
可使用下面的代码为自定义验证器实现该接口:
public clsaa MaxWordsAttribute : ValidationAttribute,IClientValidatable { public MaxWordsAttribute(int maxWords) : base("{0} has too many words.") { _maxWords = maxWords; } public int WowrdCount { get; set; } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { var valueAsString = value.ToString(); if( valueAsString.Split(' ').Length > _maxWords) { var errorMessage = FormatErrorMessage(validationContext.DisplayName); return new ValidationResult(errorMessage); } return ValidationResult.Success; } public IEnumerable<ModelClientValidationRule> GetClientValidationRules(MdelMetadata metadata,ControllerContext context) { var rule = new ModelClientValidationRule(); rule.ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()); rule.ValidationParameters.Add("wordcount", WordCount); rule.ValidationType = "maxwords"; yield return rule; } }
要实现客户端验证,需要提供如下几点信息:
- 如果验证失败,要显示的提示消息
- 允许的单词数的范围
- 一段用来计算单词数量的JavaScript代码标识。
这些信息就是嗲吗放进返回规则中的内容。请注意,如果需要在客户端触发多种类型的验证,代码可以返回多个规则。
ASP.NET MVC框架在客户端上利用GetClientValidationRules方法返回的规则将信息序列化为data-特性。
ASP.NET MVC5高级编程 之 Ajax的更多相关文章
- ASP.NET MVC5 高级编程 第5章 表单和HTML辅助方法
参考资料<ASP.NET MVC5 高级编程>第5版 第5章 表单和HTML辅助方法 5.1 表单的使用 5.1.1 action 和 method 特性 默认情况下,表单发送的是 HTT ...
- ASP.NET MVC5 高级编程 第3章 视图
参考资料<ASP.NET MVC5 高级编程>第5版 第3章 视图 3.1 视图的作用 视图的职责是向用户提供界面. 不像基于文件的框架,ASP.NET Web Forms 和PHP ,视 ...
- ASP.NET MVC5 高级编程 第2章 控制器
参考资料<ASP.NET MVC5 高级编程>第5版 第2章 控制器 控制器:响应用户的HTTP 请求,并将处理的信息返回给浏览器. 2.1 ASP.NET MVC 简介 MVC 模式中的 ...
- ASP.NET MVC5 高级编程-学习日记-第一章 入门
1.1 ASP.NET MVC 简介 ASP.NET是一种构建Web应用程序的框架,它将一般的MVC(Model-View-Controller)模式应用于ASP.NET框架. 1.1.1 MVC模式 ...
- ASP.NET MVC5高级编程 之 模型
1. 为MVC Music Store建模 Models文件夹(右击) --> 添加 --> 类 为类添加对应的属性: public class Album { public virtua ...
- 学习《ASP.NET MVC5高级编程》——基架
基架--代码生成的模板.我姑且这么去定义它,在我学习微软向编程之前从未听说过,比如php代码,大部分情况下是我用vim去手写而成,重复使用的代码需要复制粘贴,即使后来我在使用eclipse这样的IDE ...
- ASP.NET MVC5高级编程 之 视图
1.1理解视图约定 当创建一个项目模版时,可以注意到,项目以一种非常具体的方式包含了一个结构化的Views目录.在每一个控制器的View文件夹中,每一个操作方法都有一个同名的视图文件与其对应.这就提供 ...
- ASP.NET MVC5高级编程 之 HTML辅助方法
Html属性调用HTML辅助方法,Url属性调用URL辅助方法,Ajax属性调用Ajax辅助方法. HTML辅助方法 1.Html.BeginForm @using (Html.BeginForm(& ...
- ASP.NET MVC5高级编程 之 路由
每个ASP.NET MVC应用程序都需要路由来定义自己处理请求的方式.路由是MVC应用程序的入口点.路由的核心工作是将一个请求映射到一个操作 路由主要有两种用途: 匹配传入的请求(该请求不匹配服务器文 ...
随机推荐
- 在Java中调用Python
写在前面 在微服务架构大行其道的今天,对于将程序进行嵌套调用的做法其实并不可取,甚至显得有些愚蠢.当然,之所以要面对这个问题,或许是因为一些历史原因,或者仅仅是为了简单.恰好我在项目中就遇到了这个问题 ...
- Sqlserver脚本创建登录名密码
use table1 GO ', default_database=table1; GO create user abc for login abc with default_schema=dbo; ...
- mysql5.7安装(正确安装)实战
一.二进制免编译包安装 参考:http://www.apelearn.com/bbs/forum.php?mod=viewthread&tid=10105&highlight=mys ...
- Dapper.net 输出存储过程实例
1.存储过程名: public static class CampaignTrackingDomainSql { /// <summary> /// proc /// </summa ...
- cpp 内嵌函数(lambda,struct)
auto testFun = [this](int t)->void{ } []()->反回值{ } []内传入函数运行环境所用变量 ()内传入变量 捕捉块 lambda表达式的方括号部分 ...
- html页面高度问题
首先,上图 说明 1. clientHeight大部分浏览器对 clientHeight 都没有什么异议,都认为是内容可视区域的高度,也就是说页面浏览器中可以看到内容的这个区域的高度,即然是指可看到内 ...
- MacOS下安装小米SQL优化工具soar
1 下载源码包 赋予权限 wget https://github.com/XiaoMi/soar/releases/download/0.11.0/soar.darwin-amd64 -O soar ...
- python 的基础 学习 第七天 is id 编码的补充
1,== 两个等号比较的是数值,is比较的是内存地址.print(id())查看的内存地址. 小数据池只存在于数字与字符串中,数字 是 -5^^256,是为了节省空间. 字符串1,如果含有特殊字符 ...
- Javascript入门(二)变量、获取元素、操作元素
一.变量 Javascript 有五种基本数据类型 number.String.boolean.undefined.null 一种复合类型:object 二.使用getElementById方法获取元 ...
- Maven多模块项目管理小结
原文地址:http://blog.csdn.net/whuslei/article/details/7989102 题记 最近刚完成一个用Maven构建的Web项目,看了一些Maven方面的书,比如& ...