Asp.Net MVC 使用 Ajax

Asp.Net MVC 使用 Ajax

Ajax

簡單來講Ajax是一個無需從新加載整個網頁的狀況下,能夠更新局部頁面或數據的技術(異步的發送接收數據,不會干擾當前頁面)。javascript

Ajax工做原理

Ajax使瀏覽器和服務器之間多了一個Ajax引擎做爲中間層。經過Ajax請求服務器時,Ajax會自行判斷哪些數據是須要提交到服務器,哪些不須要。只有肯定須要從服務器讀取新數據時,Ajax引擎纔會向服務器提交請求。css

Ajax原理

Ajax幾個特色

  1. 不須要提交整個頁面就能夠更新數據。
  2. 與服務器異步通訊。
  3. Ajax請求不能後退,瀏覽器沒有歷史記錄。
  4. Ajax請求的頁面不能加入到收藏夾。

Jquery中的Ajax

JQuery 對 Ajax 作了大量的封裝,不須要去考慮瀏覽器兼容性,使用起來也較爲方便。html

jquery對Ajax一共有三層封裝。java

  • 最底層:$.ajax()。jquery

  • 第二層:.load()、$.get()和$.post()。ajax

  • 最高層: $.getScript()和$.getJSON()方法。json


$.Ajax()

$.Ajax()是全部Ajax方法中最底層的方法,其餘的都是基於$.Ajax()方法的封裝,該方法只有一個參數-JQueryAjaxSettings(功能鍵值對)。瀏覽器

$.Ajax參數JQueryAjaxSettings介紹:緩存

參數 類型 說明
url String 請求的地址
type String 請求方式:POST 或 GET,默認 GET
timeout Number 設置請求超時的時間(毫秒)
data Object或String 發送到服務器的數據,鍵值對或字符串
dataType String 從服務器返回的數據類型,好比 html、xml、json 等
beforeSend Function 發送請求前可修改 XMLHttpRequest 對象的函數
complete Function 請求完成後調用的回調函數
success Function 請求成功後調用的回調函數,先執行success再執行complete
error Function 請求失敗時調用的回調函數,先執行error再執行complete
global Boolean 默認爲 true,表示是否觸發全局 Ajax
cache Boolean 設置瀏覽器緩存響應,默認爲 true。若是 dataType類型爲 script 或 jsonp 則爲 false。
content DOM 指定某個元素爲與這個請求相關的全部回調函數的上下文。
contentType String 指 定 請 求 內 容 的 類 型 。 默 認 爲application/x-www-form-urlencoded。
async Boolean 是否異步處理。默認爲 true,false 爲同步處理
processData Boolean 默認爲 true,數據被處理爲 URL 編碼格式。若是爲 false,則阻止將傳入的數據處理爲 URL 編碼的格式。
dataFilter Function 用來篩選響應數據的回調函數。
ifModified Boolean 默認爲 false,不進行頭檢測。若是爲true,進行頭檢測,當相應內容與上次請求改變時,請求被認爲是成功的。
jsonp String 指定一個查詢參數名稱來覆蓋默認的 jsonp 回調參數名 callback。
username String 在 HTTP 認證請求中使用的用戶名
password String 在 HTTP 認證請求中使用的密碼
scriptCharset String 當遠程和本地內容使用不一樣的字符集時,用來設置 script 和 jsonp 請求所使用的字符集。
xhr Function 用來提供 XHR 實例自定義實現的回調函數
traditional Boolean 默認爲 false,不使用傳統風格的參數序列化。如爲 true,則使用

代碼示例:服務器

$('button').click(function(){
    $.ajax(
        {
            type:'post',
            url:'test',
            data:{
                url:'hello',
            },
            dataType:'json',
            success:function(data,stutas,xhr){
                alert(data);
            },
            error:function(xhr, textStatus, data)){
                alert(data);
            },
            complete:function(xhr,textStatus){
                alert(textStatus);
            }
        }
    )
});

$.Ajax的回調函數介紹:

  • success

Function( Anything data, String textStatus, jqXHR jqXHR )

請求成功後執行的回調函數。

參數 類型 說明
data anything 從服務器返回的數據,並根據dataType參數類型處理後的數據(默認是json)
textStatus string 描述狀態的字符串
jqxhr jqXHR XMLHTTPRequest對象
  • error

Function( jqXHR jqXHR, String textStatus, String errorThrown )

請求失敗是執行的回調函數

參數 類型 說明
errorThrown string HTTP狀態的文本部分
textStatus string 描述錯誤信息的字符串
jqxhr jqXHR 描述發生錯誤類型的一個字符串 和 捕獲的異常對象
  • complete

Function( jqXHR jqXHR, String textStatus )

請求完成後執行的回調函數,不論是成功仍是失敗都執行。

參數 類型 說明
errorThrown string HTTP狀態的文本部分
textStatus string 描述請求狀態的字符串
jqxhr jqXHR XMLHTTPRequest對象

$.load()

從服務器獲取數據而且將返回的HTML代碼插入至匹配的元素中。

$('Element').load(url,data,success(responseText,textStatus,XMLHttpRequest))
參數 類型 說明
url string 必須 請求地址
data Json或者string 可選 請求數據 若是是json該load方法是post請求,默認是get請求
success function 當請求成功後執行的回調函數
responseText string 得到字符串形式的響應數據
textStatus string 文本方式返回HTTP狀態碼
XMLHttpRequest Object xhr對象,有多種屬性

$.get()和$.post()

.load()通常在獲取靜態資源時調用,$.get()$.post()方法在須要和服務器交互數據時調用。

$.get() 方法經過 HTTP GET 請求載入信息。
這是$.ajax GET請求的簡寫方式。請求成功時可調用回調函數。

$.get(url,data,success(response,status,xhr),dataType)

使用$.get()從服務端獲取數據-代碼示例

定義model

public class PersonViewModel
{
    public int PersonID { get; set; }

    public string Name { get; set; }

    public string PhoneNum { get; set; }

    public bool IsMarried{get;set;}
    
}

定義Controller Action

public class MyAjaxController : Controller
 {   
   public JsonResult PersonList()
    {
        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 });
        }        
        return Json(persons,JsonRequestBehavior.AllowGet);
    }
 }

定義View

$.get('@Url.Action("PersonList", "MyAjax")',function (result) {
        $.each(result, function (index, person) {
            $('#myDiv').append('<p>Id: ' + person.PersonID + '</p>' +
                '<p>Name: ' + person.Name + '</p>');

        });
    });

//在Jquery1.5版本後,新增了一些事件,能夠更好的處理不一樣結果。
$.get('@Url.Action("PersonList", "MyAjax")')
    .done(function (data) {
        $.each(data, function (index, person) {
            $('#myDiv').append('<p>Id: ' + person.PersonID + '</p>' +
                '<p>Id: ' + person.Name + '</p>');
        });
    })
    .fail(function (data) {
        alert(data);
    });

$.post() 方法經過 HTTP POST 請求從服務器載入數據。

$.post(url,data,success(data, textStatus, jqXHR),dataType)

使用$.post()方法向服務端發送數據-代碼示例

定義一個Action

[HttpPost]
public JsonResult ToPersonList(IEnumerable<PersonViewModel> persons)
{
    if (persons != null)
        return Json(true);
    else return Json(false);

}

定義一個View

<script>
var results = { persons : [{ "PersonID": "1", "Name": "Manas" },
    { "PersonID": "2", "Name": "Tester" }] };
$.post('@Url.Action("ToPersonList","MyAjax")',results, function (data) {
        alert(data)
    });;
    //一樣也可使用Jquery1.5版本的新的事件
$.post('@Url.Action("ToPersonList","MyAjax")', results)
        .done(function (data) {
            alert(data);
        })
        .fail(function (data) {
            alert(data);
        })
        .always(function (data) {
            alert(data);
        })
</script>

$.get() $.post()方法都是四個參數,前面三個參數和$.load()同樣,最後一個參數dataType:服務器返回的數據格式:xml、html、script、json、jsonp和text。只有第一個參數是必須的,其餘均可覺得空。

$.get() $.post()都是$.ajax()的一個簡寫封裝,都是隻能回調success狀態,error,和complete不能被回調。可是在jquery1.5版本上,新加了jqXHR.done() (表示成功), jqXHR.fail() (表示錯誤), 和 jqXHR.always() 事件,能夠實現不一樣狀態的回調。


表單序列化

若是咱們有一個複雜的表單,一個一個獲取表單數據是一個很瑣碎的事。jquery提供了一個表單的序列化方法serialize(),會智能的獲取指定表單內的全部元素(包括單選框,複選框,下拉列表等)把表單內容序列化爲字符串。此外serializeArray()方法能夠把數據整合爲鍵值對的json對象。

若是咱們須要屢次調用$.ajax方法,而且不少參數都相同,可使用$.ajaxSetup()方法,它會把一些公共的參數預先設置好,不用每次都設置。

$('form input[type=button]').click(function () {
    $.ajaxSetup({
        type : 'POST',
        url : 'test',
        data : $('form').serialize()
    });
    $.ajax({
        success : function (response, status, xhr) {
                    alert(response);
    });
    });

在使用 data 屬性傳遞數據的時候,若是是以對象形式傳遞鍵值對,可使用$.param()方法將對象轉換爲字符串鍵值對格式。
(主要是針對沒法直接使用表單序列化方法.serialize(),且傳遞參數爲對象的狀況)


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()

異步加載一個分佈頁面

  • 定義一個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; }

    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()輔助方法,能夠異步請求加載頁面。

//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的請求。


若有不對,請多多指教。


參考資料:

相關文章
相關標籤/搜索