ASP.NET MVC之Ajax如影随行

一、Ajax的前世今生

      我一直觉得google是一家牛逼的公司,为什么这样说呢?《舌尖上的中国》大家都看了,那些美食估计你是百看不厌,但是里边我觉得其实也有这样的一个哲学:关于食材,对于种食材的菜农来讲,可能它的价值就是卖到市场上而已;而对于大厨们来讲,却可以像变魔术一样将不起眼的食材变成美味佳肴。大厨们不拥有食材,但他们却可以恰到好处的搭配使用它们,这就是他们的精明之处。而google同样是IT界的大厨:java诞生了这么多年,却没有被充分利用,而google却用它搞出来了震惊世界的Android; HTML、XML、Javascript这些个东东都不是google发明的吧,但却是google却用它们发明了Ajax, google earth、google suggest以及gmail等ajax技术的广泛应用,向这个世界带来了ajax技术,从此ajax与web再也不能分离。这里也向我们程序猿提了个醒:如果不能把所学的各种技术转化为money或者生产力,那么一切都是扯淡!

      精确的说,ajax并不能提高从服务器端下载数据的速度,而只是使这个等待不那么令人沮丧,这就是所谓的用户体验了,但就这一点就足以产生巨大的影响和震动,因为它已经革了c/s东东的命,它无疑是WEB时代的宠儿~

Ajax的给我们带来的好处大家基本上都深有体会,略表一二:

1、最大的一点是页面无刷新,在页面内与服务器通信,给用户的体验非常好。

2、使用异步方式与服务器通信,不需要打断用户的操作,具有更加迅速的响应能力。

3、可以把以前一些服务器负担的工作转嫁到客户端,利用客户端闲置的能力来处理,减轻服务器和带宽的负担,节约空间和宽带租用成本。并且减轻服务器的负担,ajax的原则是“按需取数据”,可以最大程度的减少冗余请求,和响应对服务器造成的负担。

4、基于标准化的并被广泛支持的技术,不需要下载插件或者小程序。

缺点也有,但是瑕不掩瑜,所以还是要用!ASP.NET MVC作为微软的当家利器自然也要拥抱Ajax了,这里就说说他们之间那些事儿!

二、ASP.NET MVC之Ajax

这里不会用原生的Ajax的,其实我连说都不想说,土的掉渣,更别提那个微软自己的那个已经玩完的Ajax框架了,所以下面的Ajax都不是原生的。

1、基于AjaxHelper的Ajax

MVC框架本身提供了AjaxHelper类用于Ajax异步请求,所以如果你想省事,就用这种方式吧~

AjaxHelper帮助器方法:

Helper method

Description

Ajax.ActionLink

Creates a hyperlink to a controller action that fires an Ajax request when clicked

Ajax.RouteLink

Similar to Ajax.ActionLink, but generates a link to a particular route instead of a named controller action

Ajax.BeginForm

Creates a form element that submits its data to a particular controller action using Ajax

Ajax.BeginRouteForm  Similar to Ajax.BeginForm, but creates a form that sub- mits its data to a particular route instead of a named control- ler action
 Ajax.GlobalizationScript  Creates an HTML script element that references a script that contains culture information
 Ajax.JavaScriptStringEncode  Encodes a string to make sure that it can safely be used inside JavaScript

上面的方法貌似很多,但是实际开发中用到的就两个帮助器方法而已:

 Ajax.ActionLink()和Ajax.BeginForm()

这里有个问题:怎样让项目知道我们用的是MVC自带的Ajax呢?

SO EASY:

A、在Web.config里边配置:

<add key="UnobtrusiveJavaScriptEnabled" value="true" />

B、在页面中引用下面的js类库即可:

@section scripts{
    <script type="text/javascript" src=" @Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")"></script>
}

一般更为常见的是在布局页/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>

Ajax.ActionLink()

  向客户端输出一个链接地址,当单击这个链接时可以Ajax调用Controller中的方法,Ajax.ActionLink()方法有许多重载,下面是其重载之一:

  public static string ActionLink(this AjaxHelper ajaxHelper, string linkText, string actionName, object routeValues, AjaxOptions ajaxOptions);

  linkText:是显示在客户端的文本

  actionName:是Action的名字,默认情况下我们会使用当前的Controller。

  routeValues:将传入到Controller中方法的参数

  ajaxOptions:配置Ajax的一些选项

Confirm

获取或设置提交请求之前,显示在确认窗口中的消息。

HttpMethod

获取或设置 HTTP 请求方法(“Get”或“Post”)。

InsertionMode

获取或设置指定如何将响应插入目标 DOM 元素的模式。
LoadingElementId 

获取或设置加载 Ajax 函数时要显示的 HTML 元素的 id 特性。

OnBegin

获取或设置更新页面之前,恰好调用的 JavaScript 函数的名称。

OnComplete

获取或设置实例化响应数据之后但更新页面之前,要调用的 JavaScript 函数。

OnFailure

获取或设置页面更新失败时,要调用的 JavaScript 函数。

OnSuccess

获取或设置成功更新页面之后,要调用的 JavaScript 函数。

UpdateTargetId

获取或设置要使用服务器响应来更新的 DOM 元素的 ID。

Url

获取或设置要向其发送请求的 URL。

 


备注:

  • OnComplete和OnSuccess的区别:OnComplete是获取了Http请求时引发的,此时页面还没有进行更新,OnSuccess是在页面已经更新后引发的。
  • 当加载数据须要花较长时候,为了避免假死状况,该当给用户一个反馈信息,如“正在加载...”字样。在 MVC 的 Unobtrusive Ajax 中经用AjaxOptions选项的 LoadingElementId 和 LoadingElementDuration 两个属性可轻松做到这一点,例如下面的设置:
AjaxOptions ajaxOpts = new AjaxOptions {
        UpdateTargetId = "tableBody",
        Url = Url.Action("GetPeopleData"),
        LoadingElementId = "loading",
        LoadingElementDuration = 1000,
    };
  • 对于URL,如果我们设置如下:
AjaxOptions ajaxOpts = new AjaxOptions {
        UpdateTargetId = "tableBody",
        Url = Url.Action("GetPeopleData")
    };

然后查看它生成的 form 属性:

<form id="form0" action="/People/GetPeople" method="post" data-ajax-url="/People/GetPeopleData" data-ajax-="#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,自然访问该页面。固然局部未能刷新,但不会让用户体验很差。


 使用Html.ActionLink方法的一个栗子:

@Ajax.ActionLink("点击我", "getEntry", new { id = item.Id }, new AjaxOptions 
{ HttpMethod = "Post", UpdateTargetId = "detailsID", InsertionMode = InsertionMode.Replace })

说明:“点击我”是生产的超链接文字;“getEntry”是当前控制器的Action方法;id = item.Id是向Action方法传递的参数;HttpMethod = "Post", 说明Ajax请求是post方式的;UpdateTargetId = "detailsID"说明了要更新的html块的Id标记元素;InsertionMode = InsertionMode.Replace说明是替换ID为detailsID的元素里边的内容。

实际应用:

 (1)使用Ajax.ActionLink请求返回值为 Json格式的Controller方法

 在Index.cshtml中使用ActionLink,如下:

@Ajax.ActionLink("点击我", "JsonDetails", new { id = item.Id }, 
new AjaxOptions { HttpMethod = "Post", InsertionMode = InsertionMode.Replace, OnSuccess = "Show" })

相应的Controller:

public ActionResult JsonDetails(int id = 0)
        {
            GuestbookEntry entry = _db.Entries.First(c => c.Id == id);
            return Json(entry, JsonRequestBehavior.AllowGet);
        }

同时需要在Index.cshtml中添加请求成功的相应js函数Show,以便更新ID属性为detailsID的DIV内容:

<script type="text/javascript">
function Show(data) {
$("#detailsID").html("姓名:" + data.Name + " 消息:" + data.Message);
}
</script>

(2)使用Ajax.ActionLink 请求返回值为PartialView格式的Controller方法

 在Index.cshtml中

@Ajax.ActionLink("AjaxPartialView", "Details", new { id = item.Id }, 
new AjaxOptions { HttpMethod = "Get", UpdateTargetId = "detailsID" })

相应的Controller:

public ActionResult Details(int id = 0)
        {
            GuestbookEntry entry = _db.Entries.First(c => c.Id == id);
            if (Request.IsAjaxRequest())
           {
                return PartialView(entry);
            }
            return View(entry);
        }

在这里我们使用Request.IsAjaxRequest()来判断是否为Ajax请求,如果是则返回PartialView,否则返回View。最后,返回的内容会直接更新到ID属性为detailsID的DIV中。

Ajax.BeginForm

 这个方法用于异步提交表单,比如一个新增信息的页面Create.cshtml,下面的代码会使表单以Ajax方式提交

@model MvcApplication5.Models.GuestbookEntry
<script type="text/javascript" src=" @Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")"></script>
<script type="text/javascript">
    function success(data) {
        alert(data);
    }
</script>
@{
    ViewBag.Title = "Create";
}

<h2>Create</h2>

@using (Ajax.BeginForm(new AjaxOptions { 
    HttpMethod="Post",
    OnSuccess = "success"
}))
{
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>GuestbookEntry</legend>
        <div class="editor-label">
            @Html.LabelFor(model => model.Name)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Name)
            @Html.ValidationMessageFor(model => model.Name)
        </div>
        <div class="editor-label">
            @Html.LabelFor(model => model.Message)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Message)
            @Html.ValidationMessageFor(model => model.Message)
        </div>
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}

控制器的代码如下:

        [HttpPost]
        public ActionResult Create(GuestbookEntry entry)
        {
            if (ModelState.IsValid)
            {
                entry.DateAdded = DateTime.Now;
                _db.Entries.Add(entry);
                _db.SaveChanges();
                return Content("New Entry successfully added.");
            }
            else {
                return View();
            }
        }

注:

貌似上面的Ajax方法很方便,但是它的工作原理可能大家不是很清楚,这里就大概说一下吧~

当调用 Ajax.BeginForm 方法后,经由选项 AjaxOptions 对象设置的属性将会被转化成 form 表单的属性,这些属性以 data-ajax 开首,如本示例生成的 form 表单:

<form action="/GuestBook/Create" data-ajax="true" data-ajax-mode="replace" data-ajax-="#tableBody" id="form0" method="post">

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

2、基于JQuery的Ajax

(1)使用JQuery的Ajax请求返回值为 Json格式的Controller方法

 原理就是用JQuery的Ajax方法请求Action方法,返回值设为JSON,然后对JSON数据进行处理,例如用js函数进行处理

 举个栗子: 

<script type="text/javascript" language="javascript">
        $(function(){
                GetRoomInfoList();
}); function GetRoomInfoList() { showDivLoading();
//异步加载数据时的浮层 $.ajax({ type: "Post", url: "@Url.Content("~/Room/GetRoomInfoShipId")",//异步请求的URL,就是Room控制器方法GetRoomInfoShipId(long shipId) dataType: "json",//要求返回数据为JSON格式 data:{shipId:$("#ShipIdForSearch").val()},//异步请求的参数 success: function(data){ $("#RoomInfoListTable").empty(); //清空里面的所有内容 $.each(data, function(i, item){ //用js拼字符串处理数据,这里是显示所有房型列表信息 var str="<tr>"; str+=" <td>"; str+=" <span style=\" width:150px;display:block;white-space:nowrap; overflow:hidden; text-overflow:ellipsis;\">"; str+=item.BaseRoomId; str+=" </span>" str+=" </td>"; str+=" <td>"; str+=" <span style=\" width:150px;display:block;white-space:nowrap; overflow:hidden; text-overflow:ellipsis;\">"; str+=item.ShipId; str+=" </span>" str+=" </td>"; str+=" <td>"; str+=" <span style=\" width:150px;display:block;white-space:nowrap; overflow:hidden; text-overflow:ellipsis;\">"; str+=item.RoomType; str+=" </span>" str+=" </td>"; str+=" <td>"; str+=" <span style=\" width:150px;display:block;white-space:nowrap; overflow:hidden; text-overflow:ellipsis;\">"; str+=item.RoomName; str+=" </span>" str+=" </td>"; str+="</tr>"; $("#RoomInfoListTable").append(str);
}); } }); }

(2)使用JQuery的Ajax 请求返回值为PartialView格式的Controller方法

 假设有这样的一个Model:

namespace MvcApplication1.Models
{
  public class Team
    {
        public string Preletter { get; set; }
        public string Name { get; set; }
    }
}

 通过JQuery异步加载分部视图,Home/Index.cshtml:

@{
    ViewBag.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
<div>
<a href="#" id="a">通过jQuery异步</a> <br/>
</div>
<div id="result">
</div>
@section scripts
{
   <script type="text/javascript">
     $(function() {
     $('#a').click(function() {
         $.ajax({
         url: '@Url.Action("Index","Home")',
         data: { pre: 'B' },
         type: 'POST',
         success: function(data) {


                        $('#result').empty().append(data);


                    }
                });

                return false;
            });
        });
    </script>
}

HomeController控制器中:

using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using MvcApplication1.Models;
namespace MvcApplication1.Controllers
{
    public class HomeController : Controller
       {
        public ActionResult Index()
        {
            return View();
        }
        [HttpPost]
        public ActionResult Index(string pre)
        {
            var result = GetAllTeams().Where(t => t.Preletter == pre).ToList();
            ViewBag.msg = "通过jQuery异步方式到达这里~~";
            return PartialView("TeamY", result);
        }
        private List<Team> GetAllTeams()
        {
            return new List<Team>()
            {
                new Team(){Name = "巴西队", Preletter = "B"},
                new Team(){Name = "克罗地亚队", Preletter = "K"},
                new Team(){Name = "巴拉圭", Preletter = "B"},
                new Team(){Name = "韩国", Preletter = "K"}
            };
        }
    }
}

分部视图TeamY.cshtml:

@model IEnumerable<MvcApplication1.Models.Team> 
@{
    var result = string.Empty;
    foreach (var item in Model)
    {
        result += item.Name + ",";
    }
}
@ViewBag.msg.ToString()
<br/>
@result.Substring(0,result.Length - 1)

3、基于JQuery的表单异步提交

 举个栗子吧:

<script type="text/javascript">
    $(document).ready(function () {
        $("#form1").submit(function (event) {
            event.preventDefault();//阻止默认提交事件,改用JS处理提交事件
$.ajax({
type:"Post//表单提交类型 
url: "@Url.Content("~/User/Create")",//表单提交的Action方法
data:$("#form1").serialize(), //序列化表单的值为字符串,前提是表单里边的输入标签都要有name属性才可以,序列化后的形式大概是这样的:a=1&b=2&c=3&d=4&e=5
success:function(msg){
$("#result").html(msg);    
}
});
           
return false;
});   
});
</script>

但是我觉得如果表单提交的数据少的话,可以用这种,如果多的话,就没有必要了,用MVC自带的更好

三、如何提高Ajax性能

1、适当使用缓存机制

2、使用CDN内容分发来访问Jquery脚本:

     (1)自己公司架设CDN服务器

     (2)使用第三方公司的,比如微软,谷歌等公司的CDN,但有时候不太靠谱

3、JS/CSS文件的打包合并(Bundling)及压缩(Minification)

将多个JS或CSS文件打包合并成一个文件,并在网站发布之后进行压缩,从而减少HTTP请求次数,提高网络加载速度和页面解析速度。压缩功能实现了对javascript脚本和CSS进行压缩的功能,它能够去除脚本或样式中不必要的空白和注释,同时能够优化脚本变量名的长度

例如在BundleConfig.cs里面配置捆绑js和css文件:

using System.Web;
using System.Web.Optimization;

namespace MvcExample
{
    public class BundleConfig
    {
        // For more information on Bundling, visit http://go.microsoft.com/fwlink/?LinkId=254725
        public static void RegisterBundles(BundleCollection bundles)
        {
            bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
                        "~/Scripts/jquery-{version}.js"));

            bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.css"));
        }
    }
}

 记得在Global.asax中注册一下:

BundleConfig.RegisterBundles(BundleTable.Bundles);

页面引用时可以这样引用:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
    @Styles.Render("~/Content/css")
    @Scripts.Render("~/bundles/jquery")
    @RenderSection("scripts", required: false)
</head>
<body>
    @RenderBody()
</body>
</html>

启用JS/CSS文件压缩合并:

  • Web.config中配置
<compilation debug="false" targetFramework="4.0" />
  • 在BundleConfig.cs或Global.asax中添加以下代码即可:
BundleTable.EnableOptimizations = true;

4、最好将js脚本文件放在view页面下面一点

关于ASP.NET MVC和Ajax的故事,暂且讲到这里吧!

posted @ 2014-07-04 10:34  掉进书洞里的猫  阅读(...)  评论(...编辑  收藏