Asp.Net MVC 使用 Ajax(二)

484 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

MVC中的Ajax使用

Asp.Net MVC中包含了一组Ajax辅助方法。可以用来创建异步执行的表单和指向控制器操作的异步链接。当使用这个辅助方法时,不用编写任何脚本代码来实现程序的异步。该辅助方法依赖于非侵入式MVC的jquery扩展。如果使用这些辅助方法时,需要引入脚本jquery.unbotrusive-ajax.js (可以在NuGet中获得)

分部渲染

Asp.Net MVC中的分部页面可以是partialPage也可以是含有布局(layout)的完整页面。只是在return的时候返回类型是PartialView

绝大部分情况下,部分页面的请求和完整页面的请求是一样的流程-请求被路由到指定控制器,控制器执行特定的业务逻辑,返回给对应的试图。 我们可以在控制器中使用Request.IsAjax来区别是否是ajax请求,是否是要返回分部试图,还是完整试图。分部试图(return PartialView)是render和返回了该页面的html。但是完整试图(return View)是返回了包括页面资源(css,js)和布局的所有html。

Ajax.Load()

异步加载一个分布页面

  • 定义一个ViewMode
 //Model
[Bind(Exclude = "PersonID")]
public class PersonViewModel
{
    [ScaffoldColumn(false)]
    public int PersonID { get; set; }

    [Display(Name = "姓名")]
    [Required(ErrorMessage = "不能为空")]
    public string Name { get; set; }

    [Display(Name = "手机号")]
    [Required(ErrorMessage = "不能为空")]
    [DataType(DataType.PhoneNumber)]
    public string PhoneNum { get; set; }

    public bool IsMarried{get;set;}
}
定义主页面View
//Main View:
@{
    ViewBag.Title = "主页面";
}
<h2>主页面</h2>
<p>列表详细信息</p>
<div id="partialDiv"></div>
<script>
    $('#partialDiv').load('@Url.Action("ListPage", "MyAjax")')
</script>
  • 定义分部页面View
//分部页面
@{
    ViewBag.Title = "ListPage";
}
@model IList<WebApp.Models.PersonViewModel>
<h2>分布页</h2>
<table class="table table-striped">
    <thead>
        @{ WebApp.Models.PersonViewModel p = null;}
        <tr>
            <th>@Html.LabelFor(m => @p.Email)</th>
            <th>@Html.LabelFor(m => @p.Name)</th>
            <th>@Html.LabelFor(m => @p.Home)</th>
            <th>@Html.LabelFor(m => @p.IsMarried)</th>
            <th>@Html.LabelFor(m => @p.Height)</th>
            <th>@Html.LabelFor(m => @p.PhoneNum)</th>
            @*也可以使用DisplayNameFor来显示表头*@
            @*<th>@Html.DisplayNameFor(m => Model[0].Email)</th>
            <th>@Html.DisplayNameFor(m => Model[0].Name)</th>
            <th>@Html.DisplayNameFor(m => Model[0].IsMarried)</th>
            <th>@Html.DisplayNameFor(m => Model[0].Height)</th>
            <th>@Html.DisplayNameFor(m => Model[0].PhoneNum)</th>*@
        </tr>

    </thead>
    <tbody>
        @foreach (var item in Model)
        {
            <tr>
                <td>@item.Email</td>
                <td>@item.Name</td>
                <td>@item.Home</td>
                <td>@item.IsMarried</td>
                <td>@item.Height</td>
                <td>@item.PhoneNum</td>
            </tr>
        }
    </tbody>
</table>
  • 定义一个Action
//Controller
 public class MyAjaxController : Controller
 {
    //主页面
    public ActionResult MainPage()
    {

        return View();
    }
    //分部页面
    public ActionResult ListPage()
    {
        IList<PersonViewModel> persons = new List<PersonViewModel>();
        for (int i = 0; i < 10; i++)
        {
            persons.Add(new PersonViewModel() { Email = "email" + i, Name = "name", IsMarried = false, PhoneNum = "1234" + i, Home = CityEnum.BJ, Height = i });
        }
        if (Request.IsAjaxRequest())
        {
            return PartialView(persons);
        }

        return View(persons);
    }
 }

当请求主页面的时候,会把分布页面异步加载到主页面的<div id="partialDiv"></div>


Ajax.ActionLink()

Ajax.ActionLink()辅助方法,可以异步请求加载页面。

//Main view 主页面
@{
    ViewBag.Title = "MainPage";
}
<h2>主页面</h2>
<p>列表详细信息</p>
@Ajax.ActionLink("加载详细列表", "ListPage", new AjaxOptions { UpdateTargetId = "partialDiv", InsertionMode = InsertionMode.Replace, HttpMethod = "Get" })
<div id="partialDiv"></div>

Asp.Net MVC 提供了多个AjaxOptions的属性,方法给我们使用,免去了不少js代码。

名称说明
Confirm获取或设置在提交请求之前显示在确认窗口中的消息。
HttpMethod获取或设置 HTTP 请求方法(“Get”或“Post”)。
InsertionModel获取或设置指定如何将响应插入目标 DOM 元素的模式。插入模式(“InsertAfter”、“InsertBefore”或“Replace”)。 默认值为“Replace”。
LoadingElementDuration获取或设置一个值(以毫秒为单位),该值控制在显示或隐藏加载元素时的动画持续时间。
LoadingElementId获取或设置在加载 Ajax 函数时要显示的 HTML 元素的 id 特性。
OnBegin获取或设置要在更新页面之前立即调用的 JavaScript 函数的名称
OnComplete获取或设置在实例化响应数据之后但在更新页面之前,要调用的 JavaScript 函数。
OnFailure获取或设置在页面更新失败时要调用的 JavaScript 函数。
OnSuccess获取或设置在成功更新页面之后要调用的 JavaScript 函数。
UpdateTargetId获取或设置要使用服务器响应来更新的 DOM 元素的 ID。
Url获取或设置要向其发送请求的 URL。

Ajax表单提交

当我们使用jquery的ajax提交表单时,需要在click事件中添加e.preventDefault()或者把<input type="submit" value="提交" />改为<input type="button" value="提交" />。否则会刷新页面。如下代码所示,

<form class="form-horizontal" role="form" method="post" id="myform">
    <div>
        <label for="i1">张三</label>
        <input type="text" name="i1" id="i1" />
    </div>
    <div>
        <label for="i2">李四</label>
        <input type="text" name="i2" id="i2" />
    </div>
    <div>
        <label for="i3">王二</label>
        <input type="text" name="i3" id="i3" />
    </div>
    //或者使用<input type="button" value="提交" />,不必再阻止事件的传递了。
    <input type="submit" value="提交" />
</form>
<script>
   $("input[type=submit]").click(function (e) {
        e.preventDefault();//阻止事件传递
        $.post("@Url.Action("CheckNameByAjax")", $("#myform").serialize(), function (result) {
            alert(result);
        });
    });
</script>

Asp.Net MVC提供了Ajax的表单辅助方法,可以更简单快速的实现表单的ajax提交。

@using (Ajax.BeginForm("AjaxForm", "MyAjax", new AjaxOptions { HttpMethod = "Post", OnComplete = "foo", OnSuccess = "succ", OnFailure = "fail" }, new { role = "form" }))
{
    <div>
        <label for="i1">张三</label>
        <input type="text" name="i1" id="i1" />
    </div>
    <div>
        <label for="i2">李四</label>
        <input type="text" name="i2" id="i2" />
    </div>
    <div>
        <label for="i3">王二</label>
        <input type="text" name="i3" id="i3" />
    </div>
    <input type="submit" value="提交" />
}

Ajax数据验证

在注册有时需要保证用户名或者邮箱唯一或者是否合法,这个验证又必须放在服务端完成。可以使用ajax异步请求,在用户添加完用户名或者邮箱的时候立即在服务端验证并告知用户结果,而不用填完整个表单,再去验证唯一合法性。

  • 定义一个ViewModel
//Model
[Bind(Exclude = "PersonID")]
public class PersonViewModel
{
    [ScaffoldColumn(false)]
    public int PersonID { get; set; }

    [Display(Name = "姓名")]
    [Required(ErrorMessage = "不能为空")]
    public string Name { get; set; }

    [Display(Name = "手机号")]
    [Required(ErrorMessage = "不能为空")]
    [DataType(DataType.PhoneNumber)]
    public string PhoneNum { get; set; }
}
  • 定义试图View
//view
@model NameSpace.PersonViewModel
<form class="form-horizontal" role="form" method="post" id="myform">
    <div>
        <div class="form-group">
            @Html.LabelFor(m => m.Name, new { @class = "control-label col-md-3" })
            <div class="col-md-9">
                @Html.TextBoxFor(m => m.Name, new { @class = "form-control" })
                @Html.ValidationMessageFor(m => m.Name, "", new { @class = "text-danger" })
            </div>
        </div>
        <div>
            <input type="submit" value="提交" class="btn btn-success" id="sure" />
        </div>
    </div>
</form>
<script>
    $("#Name").change(function () {
        $.ajax({
            url: "@Url.Action("CheckUserName")",
            type: "post",
            data: { Name: $("#Name").val() },
            dataType: "JSON",
            success: function (response, stutas, xhr) {
                alert(response+status + xhr.statusText);
            },
            error: function (xhr, stutas, response) {
                alert(response + status + xhr.statusText);
            },
            complete: function (data) {
                alert(data.status+data);
            },
        });
    });
    </script>
  • 定义一个Action校验用户名的唯一和合法性
[HttpPost]
//参数一定要和ViewModel的属性名称一致
public JsonResult CheckUserName(string Name)
{
    bool result = true;
    if (Name == "admin")
    {
        result = false;
    }
    return Json(result);
}

至此我们实现了Ajax的用户名唯一性和合法性的校验。但是 Asp.Net MVC 提供了一个更简单的方法,可以用更少的代码实现一样的功能

  • 在属性上添加[Remote("MethodName", "ControllerName")]特性

该特性允许客户端调用服务端的方法。 修改Model

[Bind(Exclude = "PersonID")]
    public class PersonViewModel
    {
        [ScaffoldColumn(false)]
        public int PersonID { get; set; }

        [Display(Name = "姓名")]
        //添加Remote特性
        [Remote("CheckUserName", "ControllerName",ErrorMessage="用户名已存在")]
        [Required(ErrorMessage = "不能为空")]
        public string Name { get; set; }

        [Display(Name = "手机号")]
        [Required(ErrorMessage = "不能为空")]
        [DataType(DataType.PhoneNumber)]
        public string PhoneNum { get; set; }
    }

我们只需添加一个Remote特性就可以实现用户名的服务端验证。节省了js的代码。

  • 修改Action

Asp.Net MVC默认是不允许Get请求Json(防止Json被劫持)。所以如果你需要Get请求Json。必须添加JsonRequestBehavior.AllowGet。且该数据不那么重要。

//Action
public JsonResult CheckUserName(string Name)
{
    //参数一定要和属性名称一致
    bool result = true;
    if (Name == "admin")
    {
        result = false;
    }
    //添加JsonRequestBehavior.AllowGet
    return Json(result, JsonRequestBehavior.AllowGet);
}

Asp.Net MVC Ajax辅助方法可以让我们更简便的使用Ajax。但是也要理解本身Ajajx的请求。