[翻译]《ASP.NET MVC 3 高级编程》第八章:AJAX(Professional ASP.NET MVC 3 --- Chapter 8: AJAX)...

忙不是理由,好久没更新,懒惰了不少。感谢各位(@春華秋實、@三桂)督促我更新排版结构,O2DS敬上。

索引
jQuery

  • jQuery特点
  • 不唐突JavaScript
  • 使用jQuery

AJAX助手

  • AJAX ActionLinks
  • HTML5属性
  • AJAX表单

客户端验证

  • 自定义验证

独立助手

  • jQuery UI
  • JSON和jQuery模板

改善AJAX性能

  • 使用内容分发网络(CDN)
  • 脚本优化


小结


关注焦点

  • 所有你想知道的jQuery
  • AJAX Helper
  • 深入了解客户端验证
  • 使用jQuery插件

现在很少见有Web应用不使用AJAX技术的。AJAX是Asynchronous JavaScript and XML的缩写。在实践中,AJAX主张使用一切技术来构建最佳用户体验的Web应用程序。在实际使用中,使用到了一些异步通信,然后再响应时,再辅助一些有趣的动画和颜色的变化。如果你可以为用户提供更好的应用程序的用户体验,让他们可以更高效的工作,他们会更加爱你!

ASP.NET MVC 3是一个现代的Web框架,像每一个现代的Web框架一样,从一开始就会有支持AJAX的责任。其支持AJAX的核心来自于jQuery的JavaScript库。所有ASP.NET MVC3的AJAX功能都是建立并扩展自jQuery的功能。

要想明白ASP.NET MVC3中的AJAX功能怎么使用,就必须先从jQuery开始入手。

jQuery

jQuery的口号是“少写,多做”,口号完美的描述了jQuery的体验。API简洁,但是功能强大,库本身灵活而轻量级。最重要的是,jQuery支持所有现代浏览器(包括IE、Firefox、Safari、Opera和Chrome),并隐藏了很多不一致的接口(和错误),您可能会遇到针对不同的浏览器提供不同的API而提供不同的代码。使用jQuery,不仅写更少的代码,并能在更短的时间内完成工作,并且也能保证头发始终保持在头顶上。

jQuery是目前最流行的JavaScript库之一,并且依然还是一个开源项目。在jQuery.com网站上你可以找到并下载最新版本的库、文档和插件。你可以在ASP.NET MVC应用程序中找到jQuery。微软支持jQuery,当你创建一个新的MVC项目时,ASP.NET MVC项目模板会将您所需的jQuery文件放置在Scripts文件夹。

在本章中,你会看到在MVC框架中使用jQuery来实现客户端验证和异步请求等功能。在我们深入了解ASP.NET MVC底层功能之前,让我们来快速浏览下jQuery的底层功能。

jQuery特点

jQuery擅长查找、遍历和操作HTML文档内的HTML元素。一旦你找到一个元素,使用jQuery可以很容易的操作元素的事件处理程序,元素动画以及和其他元素进行AJAX交互。本节将从jQuery函数开始来探寻jQuery的功能。

jQuery函数

jQuery函数是对象,你可以通过这个对象来访问jQuery的功能。开发人员在开始使用jQuery时会为此而感到困惑。感到困惑也同样是因为函数(jQuery)的别名$符号(因为这样可以在调用jQuery功能时可以大量减少字符输入)。更令人困惑的是$机会可以接受任意类型的参数,而依据此推断出你打算调用的功能。下面是一些jQuery函数代码的典型使用方法:

$(function () {
  $(“#album-list img”).mouseover(function () {
    $(this).animate({ height: ‘+=25’, width: ‘+=25’ })
      .animate({ height: ‘-=25’, width: ‘-=25’ });
  });
});

代码的第一行调用了jQuery函数($),传递给匿名JavaScript函数一个参数。

$(function () {
  $(“#album-list img”).mouseover(function () {
    $(this).animate({ height: ‘+=25’, width: ‘+=25’ })
      .animate({ height: ‘-=25’, width: ‘-=25’ });
  });
});

jQuery会假定你提供了一个方法,并在浏览器从服务器端加载完成HTML(DOM)信息并建立完成文档对象模型时立即执行。因为在这个时候,你就可以安全而完善的执行DOM有关的脚本了。

第二行代码向jQuery函数传递了字符串参数“#album-list img”:

$(function () {
  $(“#album-list img”).mouseover(function () {
    $(this).animate({ height: ‘+=25’, width: ‘+=25’ })
      .animate({ height: ‘-=25’, width: ‘-=25’ });
  });
});

jQuery将会把这个字符串调用解释为选择器。选择器会告诉jQuery应该在DOM中查找一个什么样的元素。你可以获取这个元素的属性值,class的值,相对位置,以及其它信息。第二行的选择器告诉jQuery在这个元素的范围内查找所有ID值为“album-list”的img元素。

当选择器执行完成时,它会返回匹配到的一个或多个元素的对象。你可以通过jQuery的一些额外的方法来调用操作包装的集合中所有的元素。例如,可以为所有由此选择器匹配到的图片添加鼠标悬停事件处理程序。

jQuery利用很好的利用了JavaScript的函数编程的能力。你会发现可以将自己创造的函数作为参数传递给jQuery的方法。例如,定义mouseover方法,如果不与onmouseover事件相关联,无论如何浏览器都不会知道该怎么去触发这个方法。为了在事件触发时触发,你需要为事件传递处理的函数代码:

$(function () {
  $(“#album-list img”).mouseover(function () {
    $(this).animate({ height: ‘+=25’, width: ‘+=25’ })
      .animate({ height: ‘-=25’, width: ‘-=25’ });
  });
});

前面的例子中,当触发元素的mouseover事件时会执行animates方法。而出发当前动画的这个元素被引用为this(出发事件的元素)关键字。请注意,代码是通过向jQuery方法中传递this关键字($(this))获取的这个元素。jQuery的参数视为这个元素的引用然后通过jQuery方法进行包装并返回这个元素。

一旦jQuery返回了包装好的元素,你可以像上面一样是使用与animate类似的方法进行操纵这些元素。在示例代码中,使图片的拉伸(宽和高都增加25像素),然后缩小一些(使图片宽和高各减少25像素)。

执行这段代码时,当用户将鼠标移动到图片上时,他们会看到个微妙的提醒效果,图片先放大了然后又恢复了,这种是应用程序必须要使用的吗?不!但是简约的效果以及鲜亮的外貌,你的用户会喜欢的。

通过本章的内容,你会看到更多更为实际的功能特性。首先,让我们仔细看看你所需要使用到的jQuery功能。

jQuery选择器

选择器会根据你传入jQuery函数的字符串作为条件在DOM中搜索可匹配的元素。在前一部分,选择器使用“#album-list img”来查找图片标记。你也可以使用层叠样式表(CSS)的方式来查找元素。jQuery选择器语法派生自CSS 3.0选择器。表8-1中罗列了所有jQuery选择器支持的代码方式。

示例

含意

${"header"}

查找id为"header"的元素。

${".editor-label"}

查找所有类名为“.editor-label”的元素。

${"div"}

查找所有的

元素。

${"#header div"}

查找id为“header”的

元素。

${"#header >div"}

查找id为“header”节点的所有

子元素。

${"a:even"}

查找查找所有奇偶的锚点元素。

表中的最后一行展示了jQuery像CSS一样支持伪类。使用这个伪类可以选择到偶数或奇数的元素,访问链接你可以查看到一个完整的CSS选择器列表:

http://www.w3.org/TR/css3-selectors/。

jQuery事件

jQuery的另一个强项就是为订阅DOM中的事件提供API。虽然你也可以使用字符串在通用绑定中指定使用事件的名称,jQuery还是提供了一些常见的时间,如click、blur和submit等事件专用方法。如前所示,你可以为jQuery传递个函数告诉它事件发生时该做什么。函数可以是匿名的,就像你在“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类以及其他更多操作。下面的代码是当用户将鼠标移动到链接元素上时,添加或删除CSS的高亮类。当用户在页面上移动鼠标到锚点标记时会有不同的显示(假设你已经生成了高亮样式)。

$(“a”).mouseover(function () {
  $(this).addClass(“highlight”);
}).mouseout(function () {
  $(this).removeClass(“highlight”);
});

关于前面的代码有一些有趣的事情:

所有jQuery方法都会生成一个包裹集,如悬停的方法,也会返回相同的jQuery的包裹集。这意味着你可以继续调用jQuery方法而无需重新选择这些元素。我们将这个称为方法链接。

在jQuery中几乎你可以看到所有的常见操作。设置mouseover和mouseout的共用操作方法,你可以在其中切换不同的样式类。你可以使用一些jQuery的快捷方式和最后的代码片段将其重写为如下形式:

$(“a”).hover(function () {
  $(this).toggleClass(“highlight”);
});

多么有力量的三行代码啊——这就是jQuery的美妙之处。

jQueryAJAX

jQuery可以将你需要的所有内容通过异步请求的方式发送回你的Web服务器。你可以发起POST请求、GET请求或jQuery请求在完成时(或发生错误时)通知您。你可以使用jQuery发送和接收XML数据(AJAX中X代表XML),但是在本章中,你会看到你会看到HTML片段数据,文本或JavaScript Object Notation(JSON)等格式。jQuery使得AJAX更为容易。

事实上,jQuery改变了Web开发人员编写脚本代码的方式,让很多工作变的更为容易。

不唐突的JavaScript

在jQuery还没有出现的时候,Web流行将JavaScript代码和HTML放在同一个文件中。甚至还把JavaScript代码当成是HTML元素的属性嵌入其中。就如同下面的onclick处理程序:

<div onclick=”JavaScript:alert(‘click’);”>Testing, testingdiv>

可能你在那段日子里面也曾在嵌入标记中写过JavaScript,因为当时也再没有什么更简单的方法可以捕获点击事件。嵌入JavaScript代码虽然可以工作,但是代码会变得非常凌乱。jQuery的出现改变了这种情况,因为你可以使用另外一种更为优秀的方法来找到元素和捕获点击事件。现在你可以从HTML的属性中移除JavaScript了。事实上,你完全可以将JavaScript代码从HTML中移除出去。

不唐突的JavaScript的作用是保持JavaScript代码与HTML标记分离。将所有你需要用到的脚本代码打包到.js文件中。如果你查看源代码,将不会看到任何JavaScript代码。即使是HTML渲染代码视图,你也不会看到任何JavaScript在里面。而这个页面唯一是用脚本的标记,你会看到一个或多个

第一个标记是加载压缩过的jQuery验证插件,jQuery的验证插件已经与所有事件挂钩(如提交或获得焦点等事件),并在事件触发时执行客户端验证规则,插件还提供了一整套默认的验证规则。

Web.config中的AJAX设置

默认情况下,不唐突JavaScript和客户端验证在ASP.NET MVC应用程序中默认是启用的。尽管如此,你还是可以通过Web.config中的appSettings来配置其行为。如果你打开应用程序根目录中的Web.config文件,将会看到appSettings配置项:

如果你想将整个应用程序的功能关闭,你可以将设置更改为false。此外,你也可以他哦在视图的基础上进行设置。在某个视图中,使用HTML Helper来设置EnableClientValidation和EnableUnobtrusiveJavaScript选项来覆盖配置项中的设置。

禁用功能选项主要是为了兼容与其相依赖的Microsoft AJAX库,而不是jQuery库或自定义脚本。

第二个脚本标签包含了jQuery验证的微软不唐突适配器。这个脚本文件的源代码是MVC框架创建用来为jQuery验证适配(转换)验证元数据的(这样jQuery就能明白该做什么了)。元数据是从哪来的?首先,你还记得是如何为专辑创建编辑视图的吗?在Shared文件夹的专辑编辑模板中你需要为视图嵌入EditorForModel类。模板代码如下:

<p>
  @Html.LabelFor(model => model.Title)
  @Html.TextBoxFor(model => model.Title)
  @Html.ValidationMessageFor(model => model.Title)
p>
<p>
  @Html.LabelFor(model => model.Price)
  @Html.TextBoxFor(model => model.Price)
  @Html.ValidationMessageFor(model => model.Price)
p>

在这里TextBoxFor是关键,Helper会为模型构建基于元数据的输入。当TextBoxFor看到验证元数据,如价格和标题的Required和StringLength注释,它们会被呈现在HTML中。下面是生成Title属性的标记:

<input
data-val=”true”
data-val-length=”The field Title must be a string with a maximum length of 160.”
data-val-length-max=”160” data-val-required=”An Album Title is required”
id=”Title” name=”Title” type=”text” value=”Greatest Hits” />

在这里你又一次看到了data-属性,jquery.validate.unobtrusive脚本会利用元数据找到需要验证的元素(从data-val=true开始),并将jQuery验证插件与元素按照接口连接然后根据元数据验证规则执行验证。jQuery验证会在每次案件或焦点事件时被触发,并在错误时及时给用户发起反馈。验证插件也会在提交表单时验证错误,这也意味着你不需要在服务器请求时单独处理错误。

要更进一步了解工作中的细节,就看下一节,自定义客户端验证方案。

自定义验证

在第六章,你使用下面的代码,利用MaxWordsAttribute属性来验证一个字符串中所有的单词数量:

public class MaxWordsAttribute : ValidationAttribute
{
  public MaxWordsAttribute(int maxWords)
    :base(“Too many words in {0}”)
  {
    MaxWords = maxWords;
  }
  
public int MaxWords { get; set; }
  
protected override ValidationResult IsValid(object value,
    ValidationContext validationContext)   {     
if (value != null)     {       var wordCount = value.ToString().Split(‘‘).Length;       if (wordCount > MaxWords)       {         return new ValidationResult(           FormatErrorMessage(validationContext.DisplayName)         );       }     }     return ValidationResult.Success;   } }

你可以使用下面这段代码的属性,但是该属性只提供了服务器端的验证支持:

[Required(ErrorMessage = “An Album Title is required”)]
[StringLength(160)]
[MaxWords(10)]
public string Title { get; set; }

为了支持客户端验证,在下章我们会讨论为你的属性实现一个接口。

IClientValidatable

IClientValidatable接口定义了一个方法:GetClientValidationRules。MVC会在验证这个对象时发现这个接口,他会调用GetClientValidationRules来检索到一个ModelClientValidationRule对象的数组。这些对象会将元数据、规则通过框架发送到客户端。

你可以用下面的代码来实现自定义验证器的接口:

public class MaxWordsAttribute : ValidationAttribute,
IClientValidatable
{
…
  public IEnumerable GetClientValidationRules(
    ModelMetadata metadata, ControllerContext context)
  {
    var rule = new ModelClientValidationRule();
    rule.ErrorMessage = FormatErrorMessage(metadata.GetDisplayName());
    rule.ValidationParameters.Add(“wordcount”, WordCount);
    rule.ValidationType = “maxwords”;
    yield return rule;
  }
}

你需要确认有多少信息需要在客户端进行验证:

  • 如果验证失败,需要显示什么错误信息;
  • 允许使用多少个字;
  • 还有一段JavaScript代码的标识;

请注意,如果你需要在客户端触发多种类型的验证,你可以同时返回多个规则。

代码会从规则的ErrorMessage属性中取出错误信息。这样可让服务器的错误信息与客户端的错误信息完全匹配。ValidationParameters集合可以容纳你所需要的客户端参数,例如允许的最大字符数等。你可以把额外的参数放置到这个集合中,不但要注意它们的名称,必须符合客户端脚本中的名称。最后,在ValidationType属性会标识你需要在客户端上使用JavaScript代码。

MVC框架需要从GetClientValidationRules方法来获得规则,并序列化后设置到客户端data-属性中:

<input
data-val=”true”
data-val-length=”The field Title must be a string with a maximum length of 160.”
data-val-length-max=”160”
data-val-maxwords=”Too many words in Title”
data-val-maxwords-wordcount=”10”
data-val-required=”An Album Title is required” id=”Title” name=”Title”
type=”text” value=”For Those About To Rock We Salute You” />

请注意,maxwords是如何将属性名对应到MaxWordsAttribute属性上的,是因为你在ValidationType属性中设置了maxwords的文本(必须注意,验证的类型和所有验证参数名必须小写,因为命名必须符合HTML属性规则)。

现在,你已经具有了客户端上的元数据,但是你仍然要编写一些脚本代码来执行验证逻辑。

自定义验证脚本代码

幸运的是,你无需为客户端data-属性中的元数据而编写任何代码,但是,依然需要在验证中填写两端代码:

  • 适配器:适配器是为了匹配MVC框架的不唐突扩展部分所需要的元数据,不唐突扩展需要将data-属性中的元数据通过适配转换成为jQuery验证可以理解的值;
  • 本身的验证规则:这在jQuery中被称为验证器。

这些代码都存储同一个脚本文件中,这时假设你想将代码存入由“自定义脚本”一节所创建的MusicScripts.js文件中。在这种情况下,你需要确保MusicScript.js文件会在验证脚本载入之后再进行加载。如下使用脚本配置元素进行创建:

@section scripts
{
  <script src=”@Url.Content(“~/Scripts/jquery.validate.min.js”)”
    type=”text/JavaScript”>script>
  <script
    src=”@Url.Content(“~/Scripts/jquery.validate.unobtrusive.min.js”)”
    type=”text/JavaScript”>script>
  <script src=”@Url.Content(“~/Scripts/MusicScripts.js”)” type=”
    text/JavaScript”>
  script>
}

将这些引用代码加入到MusicScripts.js中,可以为你提供你需要的代码提示功能:

/// <reference path=”jquery-1.4.4.js” />
/// <reference path=”jquery.validate.js” />
/// <reference path=”jquery.validate.unobtrusive.js” />

第一部分代码是实现适配器的,MVC框架的不唐突验证扩展会在jQuery.validator.unobtrusive.adapters对象中存储所有适配器。你可以使用适配器对象公开的API来增加新的适配器,如表8-2所示:

表8-2:适配器方法

名称

描述

addBool

为验证器的规则创建一个“开”或“关”适配器。这个方法没有额外的参数。

addSingleVal

为验证器的规则创建一个从元数据匹配单个参数的适配器。

addMinMax

创建一个适配器映射到一组验证规则上,做一个最小值或一个最大值对比检查。或者同时对最大值、最小值一起进行数据规则检查。

add

创建一个与前面提供类型不能匹配的适配器,它需要额外的参数或额外的设置代码。

在验证最大值的情况下,你可以使用addSingleVal或AddMinMax方法(或add,因为它可以实现任何情况)。如果你不需要检查最小值的话,就可以使用addSingleVal的API,如下代码:

/// 
/// 
/// 
$.validator.unobtrusive.adapters.addSingleVal(“maxwords”, “wordcount”);

第一个参数是适配器的名称,必须与服务器端设置规则的ValidationProperty的值相同。第二个参数是用来检索元数据的参数名称。请注意,不需要在参数名中使用data-前缀;这里的参数需要与你在服务器端设置的ValidationParameters集合中的参数名相匹配。

适配器相对比较简单,它主要目的就是为不唐突扩展定位并识别元数据。有了合适的适配器,就可以写验证。

所有验证器都在jQuery.validator对象中,与适配器对象一样,新验证器也是通过验证对象的API来添加的。该方法名是“addMethod”:

$.validator.addMethod(“maxwords”, function (value, element, maxwords) {
  if (value) {
    if (value.split(‘‘).length > maxwords) {
      return false;
    }
  }
  return true;
});

这个方法需要提供两个参数:

  • 验证器名称,按照惯例应与适配器名称相匹配(和服务器上的ValidationType属性相匹配);
  • 验证发生时所需调用的函数。

验证函数会接受三个参数,可以返回真(验证通过)或假(验证失败):

  • 方法的第一个参数将包含输入的值(例如专辑的标题);
  • 方法的第二个参数是输入元素,它包含验证所需的值(在这个例子中并没有提供相应的信息);
  • 方法的第三个参数是一个包含所有验证参数的数据,在这个例子中,只包含了一个验证参数(字符串的最大长度)。

虽然ASP.NET MVC中的AJAX Helper提供了大量功能,但整个生态系统需要更多的jQuery扩展。在下一节中专门讨论这个主题。

独立助手

如果在浏览器中访问http://plugin.jquery.com,你会看到有成千上万的jQuery扩展。这些扩展大多是面向图形方面的也有很多相关方面的事情(动画方面)。或者其它类似于日期选择器或Gird的插件。

使用jQuery插件通常需要下载、解压插件并将这些插件添加到你的项目中。一些jQuery插件可以通过NuGet获得包并轻松加入到你的项目中。插件至少需要一个JavaScript文件,许多面向UI的插件可能还需要附带图像以及样式表文件。

每个ASP.NET MVC项目生成时都会有两个插件:jQuery验证(你之前使用过的)和jQuery UI(你现在要看到的)。

jQuery UI

jQuery UI是jQuery的一个插件,包含效果和Widgets。像所有插件一样,它与jQuery紧密集成并扩展了jQuery的API。下面回到本章开头的那个例子中——专辑商店的专辑封面动画代码:

$(function () {
  $(“#album-list img”).mouseover(function () {
    $(this).animate({ height: ‘+=25’, width: ‘+=25’ })
    .animate({ height: ‘-=25’, width: ‘-=25’ });
  });
});

使用jQuery UI来代替专辑封面反转的动画.第一步,你需要在应用程序的布局视图红添加jQuery UI的脚本引用标签:

<script src=”@Url.Content(“~/Scripts/jquery-1.4.4.min.js”)”
type=”text/JavaScript”>script>
<script src=”@Url.Content(“~/Scripts/jquery.unobtrusive-AJAX.min.js”)” type=”text/JavaScript”>script>
<script src=”@Url.Content(“~/Scripts/jquery-ui.min.js”)” type=”text/JavaScript”>script>

现在,你可以将mouseover事件处理程序改为下面的代码:

$(function () {
  $(“#album-list img”).mouseover(function () {
    $(this).effect(“bounce”);
  });
});

 当用户使用鼠标滑过专辑时,封面图片会在很短的时间内反转。正如你看到的,你可以使用jQuery返回的包装集来执行UI扩展插件的方法,这个方法还提供了第二个“可选”参数,它允许你通过参数来调整行为。

$(this).effect(“bounce”, { time: 3, distance: 40 });

你可以通过阅读jQuery.com插件频道的文档来了解这些可选值(以及它们的默认值)。在jQuery UI中还包含explode,fade,shake和pulsate等效果。

可选项!可选项!无处不在!

“可选项”参数会始终贯穿jQuery和jQuery插件。某些方法可能会需要6、7个不同的参数(如时间、距离、方向或模式等),你可以传递一个对象,通过对象的属性来设置参数。在前一个例子中,需要设置的只有时间和距离。该文档会始终告诉你有哪些可用的参数,并且每个参数的默认值是什么。你构造的对象只需要属性和要设置的参数相对应就好了!

jQuery UI能做的不光是特效或吸引眼球。该插件还包含像Accordion、autocomplete,按钮,日期选择器,对话框,进度条,滑动条或tabs。下一节我们会做一个自动完成的例子。

jQuery UI自动完成

作为一个widget,AutoComplete需要可以定位在屏幕的新用户界面元素上。这个元素需要在颜色、字体大小、背景和一些典型细节方面与用户界面的其他元素保持一致。jQuery UI依赖于主题来提供展示细节。jQuery UI的主题包含样式表和图片文件。每个新创建的MVC项目的Content文件夹中都会有一个base的主题,这个主题会包含样式表(jQuery-ui.css)和images文件夹中的.png文件。

在使用AutoComplete之前,你需要设置应用程序的布局视图包含base主题的样式表信息:

<link href=”@Url.Content(“~/Content/Site.css”)” rel=”stylesheet”
type=”text/css” />

<link href=”@Url.Content(“~/Content/themes/base/jquery-ui.css”)”
rel=”stylesheet”)”type=”text/css” />

<script src=”@Url.Content(“~/Scripts/jquery-1.4.4.min.js”)”
type=”text/JavaScript”>script>

<script src=”@Url.Content(“~/Scripts/jquery.unobtrusive-AJAX.min.js”)”
type=”text/JavaScript”>script>

<script src=”@Url.Content(“~/Scripts/jquery-ui.min.js”)”
type=”text/JavaScript”>script>

如果你不喜欢jQuery内置的默认主题,你可以通过访问http://jqueryui.com/themeroller/去下载主题。你还可以通过网页定制(可实时预览效果)和下载自定义的jQuery-ui.css文件。

添加行为

首先,你是否还记得在本章前面部分“艺术家搜索”功能中使用“AJAX表单”的情景?你需要使用JavaScript找到输入节点并绑定jQuery自动完成的行为。使用这个功能的方法之一就是用MVC框架的data-属性:

<input type=”text” name=”q”
data-autocomplete-source=”@Url.Action(“QuickSearch”, “Home”)” />

通过使用jQuery查找节点的data-autocomplete-source属性,这将会告诉你这个元素要一个AutoComplete的行为,并未AutoComplete部件制定一个数据源,可以让它用这个来检索候选人。AutoComplete通过指定URL获取远程数据源(获取一个对象数组)并缓存在内存中会比较容易消耗内存。控制每次从远程数据源获取艺术家的数量,发送合理的数据量到客户端。

在MusicScripts.js中,你可以使用下面的代码,在ready事件中为所有AutoComplete的data-autocomplete-source属性的输入框附加AutoComplete方法:

$(“input[data-autocomplete-source]”).each(function () {
  var target = $(this);
  target.autocomplete({ source: target.attr(“data-autocomplete-source”) });
});

jQuery的each函数会遍历所有项,在方法中,你可以为目标调用自动完成插件的方法。AutoComplete方法的参数只有一个可选参数,与大多数方法不同它还有一个必填参数——数据源属性。你可以设置其他选项,例如在按键跳起的延迟之后开始合计金额,也可以在自动完成之后发送到数据源获取所需的最小字符数。

在这个例子中,你需要指出一个控制器动作,下面是代码(只是为了防止你忘记):

<input type=”text” name=”q”
  data-autocomplete-source=”@Url.Action(“QuickSearch”, “Home”)” />

AutoComplete将会按照预期访问数据源并使用接收到的对象集合来建立一个用户列表。在HomeController中的QuickSearch动作中要返回一个autocomplete可以解析的数据。

绑定数据源

AutoComplete希望通过调用数据源并获取到JSON格式的对象。幸运的是,你在稍后会看到使用MVC控制器的动作容易就能生成一个JSON结果。对象必须有Label的属性或Value的属性,或两者都有。Autocomplete会显示用户在使用的label属性。当用户选择了自动完成列表中的项目,该部件将会把所选的内容放入输入框中。如果你不提供Label或Value,Autocomplete将会使用任意属性替代Label或value。

使用下面的代码实现QuickSearch,并返回JSON结果:

public ActionResult QuickSearch(string term)
{
  var artists = GetArtists(term).Select(a => new {value = a.Name});
  return Json(artists, JsonRequestBehavior.AllowGet);
}

private List GetArtists(string searchString)
{
  return storeDB.Artists
    .Where(a => a.Name.Contains(searchString))
    .ToList();
}

当Autocomplete调用数据源时,它会将输入项中的值作为查询字符串,你会在动作的参数中接收到这个值。你会在一个匿名类型对象中将美味艺术家转化成JSON集合并产生一个JsonResult。当框架执行结束会将这个结果序列化成JSON对象。

JSON 劫持

默认情况下,ASP.NET MVC框架是不允许在HTTP的GET请求时响应并加载JSON结果。你需要发送一个JSON的GET请求,你需要将使用JsonRequestBehavior.AllowGet作为第二个参数明确表明允许获取JSON方法。

然后,即使这样,恶意用户还是可以在访问JSON时进行JSON劫持。如果你不想在GET请求的JSON结果中返回敏感信息,你可以参看Phil的文章:

http://haacked.com/archive/2009/06/25/json-hijacking.aspx。

图8-4中显示出了您的劳动成果。

[翻译]《ASP.NET MVC 3 高级编程》第八章:AJAX(Professional ASP.NET MVC 3 --- Chapter 8: AJAX)..._第4张图片

图8-4

JSON不仅非常容易访问的控制器的动作,而且它非常轻量级。事实上,JSON请求和响应所产生的负载比同样体积的HTML或XML数据要小很多。一个很好的例子就是搜索功能。当用户点击搜索按钮时,你最终会呈现艺术家列表的局部视图。你可以使用JSON结果来代替原有视图来减少带宽用量。

从服务器检索JSON数据的核心问题是,是如何序列化对象,可以让它好呢容易的从服务器传送到页面的HTML。你需要使用原始数据在客户端构建HTML。模板是这些繁琐的传统工作更为容易。

JSONjQuery模板

jQuery模板是jQuery的插件,默认情况下并不包含在MVC3的项目中,你可以从NuGet中获得此插件。模板可以帮助你在客户端构建HTML。这个语法类似于Razor视图,从某种意义上说,你使用特殊的HTML分隔符来标识数据出现的位置,这种方法被称为占位符绑定表达式。参看下面的代码示例:

<span class=”detail”>
  Rating: ${AverageReview}
  Total Reviews: ${TotalReviews}
span>

上面的模板对应的AverageReview和TotalReviews属性对象。当渲染jQuery模板时,模板会将值放置在相应的位置。您也可以针对模板进行数据序列进行渲染。你可以通过以下地址来访问jQuery模板的文档:

http://api.jquery.com/category/plugins/templates/。

在下面的章节中,你将会使用JSON和jQuery模板来重写搜索功能。

jQuery 模板的来源

jQuery模板是由微软创作的一个jQuery官方插件的开源项目。事实上,微软正在实施几个jQuery系统的插件,包含jQuery模板、jQuery数据链接和jQuery全球化插件。

添加模板

安装jQuery模板,请右键单击MvcMusicStore项目,并选择“添加到库包引用”。在对话框(如图8-5所示)中搜索“jQuery Templates”:

[翻译]《ASP.NET MVC 3 高级编程》第八章:AJAX(Professional ASP.NET MVC 3 --- Chapter 8: AJAX)..._第5张图片

图8-5

当NuGet包添加到项目中,项目的Scripts文件夹中会多了两个新的脚本:jQuery.tmpl.js和jQuery.tmpl.min.js。在实际使用中要将插件的压缩版本发送到客户端。

<script src=”@Url.Content(“~/Scripts/jquery-1.4.4.min.js”)”
type=”text/JavaScript”>script>

<script src=”@Url.Content(“~/Scripts/jquery.unobtrusive-AJAX.min.js”)”
type=”text/JavaScript”>script>

<script src=”@Url.Content(“~/Scripts/jquery-ui.min.js”)”
type=”text/JavaScript”>script>

<script src=”@Url.Content(“~/Scripts/jquery.tmpl.min.js”)”
type=”text/JavaScript”>script>

插件放置完毕,就可以开始使用模板来实现搜索功能。

修改搜索表单

在本章的前面“AJAX表单”一节,使用AJAXHelper创建了艺术家搜索功能:

@using (AJAX.BeginForm(“ArtistSearch”, “Home”,
new AJAXOptions {
  InsertionMode=InsertionMode.Replace,
  HttpMethod=”GET”,
  OnFailure=”searchFailed”,
  LoadingElementId=”AJAX-loader”,
  UpdateTargetId=”searchresults”,
}))
{
  ”q”
    data-autocomplete-source=”@Url.Action(“QuickSearch”, “Home”)” />
  
  loader”     src=”@Url.Content(“~/Content/Images/AJAX-loader.gif”)”     style=”display:none”/> }

虽然AJAXHelper提供了很多功能,你要删除这个助手,并从头开始。jQuery提供各种从服务器检索数据的异步API。你可以利用这些功能间接来使用自动autocomplete widget等控件。

你首要改变使用jQuery AJAX Helper的搜索方式,但是控制器代码还是保持不变的(现在还没有使用JSON)。在Index.cshtml中的的新标记代码如下:

<form id=”artistSearch” method=”get” action=”@Url.Action(“ArtistSearch”, “Home”)”>
<input type=”text” name=”q”
  data-autocomplete-source=”@Url.Action(“QuickSearch”, “Home”)” />
<input type=”submit” value=”search” />
<img id=”AJAX-loader” src=”@Url.Content(“~/Content/Images/AJAX-loader.gif”)”
  style=”display:none”/>
form>

这里代码唯一的变化就是没有使用AJAXHelper的BeginForm来构建表单。没有Helper你还需要编写自己的JavaScript代码从服务器请求HTML。你可以在MusicScripts.js内写如下代码:

$(“#artistSearch”).submit(function (event) {
  event.preventDefault();
  var form = $(this);
  $(“#searchresults”).load(form.attr(“action”), form.serialize());
});

使用代码钩子的形式来提交表单。

jQuery需要调用事件传入的preventDefault方法来防止发生违约事件的行为(在这种情况下,你需要控制请求和响应,以避免直接提交到服务器)。

load方法会从URL中检索HTML然后放置到匹配的HTML元素(searchresults元素)。load方法的第一个参数表单的action属性值。第二个参数是要传送的查询字符串。jQuery的serialize方法会将表单内部的值都链接成一个字串数据。在这个例子中,你只有一个文本输入单的值,当用户输入black时,序列化会使用输入框的name和value属性,建立起查询字符串“q=black”。

获得JSON

你已经修改了代码,但是你还需要重新调整由服务器返回的HTML代码。让我们来更改HomeController控制器中的ArtistSearch动作,并返回Json,而不是局部视图:

public ActionResult ArtistSearch(string q)
{
  var artists = GetArtists(q);
  return Json(artists, JsonRequestBehavior.AllowGet);
}

现在,你需要将客户端接收脚本改为Json而不是HTML片段。jQuery提供名为getJSON的方法,你可以使用它来检索数据:

$(“#artistSearch”).submit(function (event) {
  event.preventDefault();
  var form = $(this);
  $.getJSON(form.attr(“action”), form.serialize(), function (data){
    // now what?
  });
});

相比较原来的代码,只是由原来的load方法改为调用getJSON方法,但是方法的参数并不相同。需要一个网址和一些查询字符串数据,这样会产生一个HTTP的GET请求方法,进而给第三个参数的回调方法传入一个反序列化后的JSON的对象,你需要在回调里面做些什么呢?JSON数据里面是搜索的艺术家结果的数组,但是没有标记来呈现这些艺术家。这时模板就开始发挥作用。模板是在脚本标记内嵌入的标记。下面的代码显示模板是如果来呈现搜索结果的标记:

<script id=”artistTemplate” type=”text/x-jquery-tmpl”>
  <li>${Name}</li>
script>

<div id=”searchresults”>   <ul id=”artist-list”>   ul> div>

注意脚本标记的type属性的值为“text/x-jquery-tmpl”。这样可以确保浏览器不会试图去把这些当作真正的脚本标记的内容去解释。${Name}语法是绑定表达式。绑定表达式会告诉模板引擎找到当前数据对象的属性的名称,并将其填入

  • 之间。这样就会将JSON数据呈现在标记间。

    你可以在getJSON回调方法中选择使用你需要的模板:

    $(“#artistSearch”).submit(function (event) {
      event.preventDefault();
      var form = $(this);
      $.getJSON(form.attr(“action”), form.serialize(), function (data) {
        $(“#artistTemplate”).tmpl(data).appendTo(“#artist-list”);
      });
    });

    tmpl方法能将JSON数据绑定到DOM元素中。因为JSON数据是一个artists的数组,模板引擎将会递归每个艺术家的数据,并根据代码模板输出到艺术家列表。

    客户端模板是一个强大的技术,本节只是简单的了解了一下模板引擎的基本功能。这个示例只是在实现前面AJAXHelper的功能。你是否还记得在前面“AJAXHelper”一节中会在服务器抛出一个错误时会调用一个方法,会要求Helper类呈现出来一个GIF动画,你也可以通过删除一个抽象层次来实现这些功能。

    灵活的jQuery.ajax方法

    当你需要完全控制AJAX请求就需要使用jQuery的AJAX方法。AJAX方式有一些备选参数,你可以指定一个HTTP的行为动词(GET或POST)、超时、错误处理或其他。而所有你所见过的其他异步通信方法(load或getJSON)最终需要调用AJAX方法。

    即使使用AJAX方法,你也依然可以使用AJAXHelper或客户端模板的所有功能:

    $(“#artistSearch”).submit(function (event) {
      event.preventDefault();
      var form = $(this);
      $.AJAX({
        url: form.attr(“action”),
        data: form.serialize(),
        beforeSend: function () {
          $(“#AJAX-loader”).show();
        },
        complete: function () {
          $(“#AJAX-loader”).hide();
        },
        error: searchFailed,
        success: function (data) {
          $(“#artistTemplate”).tmpl(data).appendTo(“#artist-list”);
        }
      });
    });

    调用AJAX方法比较复杂你需要定制很多的参数设置,就像为load或getJSON方法指定url和data属性一样,AJAX方法为你提供了发送和完成时的回调方法。jQuery将在完成或出错时调用这些回调方法。但是,错误和成功这两个回调方法在完成时只会有一个被执行。在这个例子中如果jQuery调用失败则会调用你在”AJAX 表单“那一节所定义的searchFailed方法,如果执行成功,你将会看到由模板设定的呈现内容。

    改善AJAX性能

    当你开始向客户端发送大量脚本代码时,你需要注意保持性能。有很多工具可以帮助你来优化网站的客户端性能,包括Firebug的YSlow(详情见http://developer.yahoo.com/yslow/)和Internet Explorer的开发工具(详情见http://msdn.microsoft.com/en-us/library/dd565629(VS.85).aspx)。在本章中,我们将会提供一些关于性能的优化技巧。

    使用内容分发网络(CDN)

    虽然你可以使用自己的服务器来分发jQuery脚本,而不考虑交给jQuery的内容交付网络(CDN)。CDN的缓存服务器分布在世界各地,使用它将会给客户带来更快的下载。因为其他网站也会从CDN引用jQuery,客户可能已经在本地拥有了文件缓存,这样做可能会为别人节省带宽成本。

    微软就是这样一个CDN提供商。微软的CDN会承载本章中使用过的所有文件。如果你想从微软的CDN服务器来获取jQuery服务而不是自己的服务器,你可以使用以下的脚本标记:

    <script src=”http://AJAX.aspnetcdn.com/AJAX/jQuery/jquery-1.4.4.min.js”
      type=”text/JavaScript”>script>

    你可以在下面的网址查找到的微软的CDN所提供的文件列表和最后发行版本:

    http://www.asp.net/AJAXlibrary/CDN.ashx

    脚本优化

    许多Web开发人员并不会在文档的head元素中使用脚本标记。相反,他们尽可能的将脚本放置在靠近页面底部。因为脚本标记放置在页面顶部的head元素中,当浏览器遇到这个脚本标记时就会下载整个脚本,这种行为会导致页面加载缓慢。可以将所有脚本标记移动到页面底部(在body标记关闭前),将可以产生更好的用户体验。

    有种技术,通过压缩自定义的脚本来减少页面加载的时间。正如本章前面“Using jQuery”中提到的,压缩JavaScript可以让下载量减少一半。微软有一个非常棒的JavaScript压缩器http://AJAXmin.codeplex.com/。

    最后,还有另外一种脚本优化技术,可以尽量减少你发送客户端的脚本内容。可与任何给定页面浏览器都回看到这些脚本标记。为了能使传输达到理想效果,你可以将多个JavaScript文件合并成单个资源。多个脚本在合并时,会在项目中创建一个新的文件,在其他脚本运行时,会在发生HTTP请求时动态结合这些内容。你可以通过以下地址访问脚本动态合并项目http://combres.codeplex.com/。

    小结

    本章走马观花式的了解了一下ASP.NET MVC3的AJAX功能。正如你所知道的,这些功能很大程度上依赖于开源的jQuery库,以及一些jQuery的常用插件。

    在ASP.NET MVC3应用程序中AJAX功能成功的关键在于对jQuery内容和jQuery如何工作的了解。jQuery灵活而强大,它允许你从页面代码中将脚本代码分离,并支持不唐突JavaScript。分离以为着你可以专注于编写更好的JavaScript代码,并发掘jQuery的更多更好的功能。

    转载于:https://www.cnblogs.com/o2ds/archive/2012/06/27/2565371.html

    你可能感兴趣的:(测试,javascript,json,ViewUI)