[ASP.NET MVC] 利用动态注入HTML的方式来设计复杂页面
隨著最終用戶對用戶體驗(yàn)需求的不斷提高,實(shí)際上我們很多情況下已經(jīng)在按照桌面應(yīng)用的標(biāo)準(zhǔn)來設(shè)計(jì)Web應(yīng)用,甚至很多Web頁面本身就體現(xiàn)為一個單一的頁面。對于這種復(fù)雜的頁面,我們在設(shè)計(jì)的時候不可以真的將所有涉及的元素通通至于某個單獨(dú)的View中,將復(fù)雜頁面相對獨(dú)立的內(nèi)容“分而治之”才是設(shè)計(jì)之道。我們可以借鑒Smart Clent應(yīng)用的設(shè)計(jì)方式:將一個Windows Form作為應(yīng)用的容器(Smart Client Shell),在操作過程中動態(tài)地激活相應(yīng)的用戶控件(Smart Part)并加載到容器中。對于一個復(fù)雜頁面來說,我們也只需要將其設(shè)計(jì)成一個容器,至于運(yùn)行過程中動態(tài)顯示的內(nèi)容則可以通過Ajax調(diào)用獲取相應(yīng)的HTML來填充。[源代碼從這里下載]
目錄
一、實(shí)例演示
二、作為容器的View
三、顯示聯(lián)系人列表
四、彈出“修改聯(lián)系人”對話框
五、聯(lián)系人信息的最終修改
一、實(shí)例演示
我們先來演示一個簡單的例子,假設(shè)我們要設(shè)計(jì)一個“聯(lián)系人”管理的頁面。該頁面初始狀態(tài)如左圖所示,它僅僅具有一個用于輸入查詢條件(First Name和Last Name)進(jìn)行聯(lián)系人查詢的表單。當(dāng)用戶輸入相應(yīng)的查詢條件之后點(diǎn)擊“Retrieve”按鈕,相應(yīng)的聯(lián)系人列表顯示以表格的形式顯示出來(中圖)。當(dāng)我們點(diǎn)擊作為ID的鏈接后,會以“模態(tài)對話框”的形式顯示當(dāng)前聯(lián)系人的編輯“窗口”(右圖)。
這個“單頁面應(yīng)用”是通過ASP.NET MVC開發(fā)的,接下來我們來逐步介紹如果將同一頁面中的這三塊不同的內(nèi)容提取出來進(jìn)行“分而治之”。
二、作為容器的View
如下所示的是表示聯(lián)系人的Contact類型的定義,沒有什么特別之處:
1: public class Contact 2: { 3: [Required] 4: public string Id { get; set; } 5: [Required] 6: public string FirstName { get; set; } 7: [Required] 8: public string LastName { get; set; } 9: [Required] 10: [DataType(DataType.EmailAddress)] 11: public string EmailAddress { get; set; } 12: [Required] 13: [DataType(DataType.PhoneNumber)] 14: public string PhoneNo { get; set; } 15: }聯(lián)系人管理對應(yīng)的HomeController定義如下。簡單起見,我們通過一個靜態(tài)字段來表示維護(hù)的聯(lián)系人列表。我們僅僅列出了默認(rèn)的Action方法Index,它會直接將作為“容器頁面”的View呈現(xiàn)出來。
1: public class HomeController : Controller 2: { 3: private static List<Contact> contacts = new List<Contact> 4: { 5: new Contact{Id = "001", FirstName = "San", LastName = "Zhang", EmailAddress = "zhangsan@gmail.com", PhoneNo="123"}, 6: new Contact{Id = "002", FirstName = "Si", LastName = "Li", EmailAddress = "zhangsan@gmail.com", PhoneNo="456"} 7: }; 8:? 9: public ActionResult Index() 10: { 11: return View(); 12: } 13: //其他Action方法 14: }如下所示的是Index.cshtml的定義,在這里使用了Twitter的Bootstrap,所示我們引用了相應(yīng)的CSS和JS。這個主體部分包含三個<div>,分別對應(yīng)著上述的三個部分。
1: <html> 2: <head> 3: <title>Contacts</title> 4: <link href="@Url.Content("~/Assets/css/bootstrap.css")" rel="stylesheet" type="text/css" /> 5: <link href="@Url.Content("~/Assets/css/bootstrap-responsive.css")" rel="stylesheet" type="text/css" /> 6: </head> 7: <body> 8: <div class="form-search"> 9: @Html.Partial("QueryFormPartial") 10: </div> 11: <div id="contactList"></div> 12: <div class="modal fade" id="contactDialog"></div> 13:? 14: <script type="text/javascript" src="@Url.Content("~/Assets/js/jquery-1.7.1.min.js")"></script> 15: <script type="text/javascript" src="@Url.Content("~/Assets/js/bootstrap.min.js")"></script> 16: <script type="text/javascript" src="@Url.Content("~/Assets/js/jquery.unobtrusive-ajax.min.js")"></script> 17: <script type="text/javascript" src="@Url.Content("~/Assets/js/jquery.validate.min.js")"></script> 18: <script type="text/javascript" src="@Url.Content("~/Assets/js/jquery.validate.unobtrusive.min.js")"></script> 19: </body> 20: </html>表示“查詢表單”的部分定義在如下所示的Partial View(QueryFormPartial.cshtml),直接通過調(diào)用HtmlHelper的Partial方法呈現(xiàn)在當(dāng)前View中。
1: @{ 2: Layout = null; 3: } 4: using (Ajax.BeginForm("Find", new AjaxOptions { OnSuccess = "renderCustomerList" })) 5: { 6: <fieldset> 7: <legend>Maintain Contacts</legend> 8: <label class="control-label" for="firstName">First Name. :</label> 9: <input type="text" name="firstName" class="input-medium search-query" /> 10: <label class="control-label" for="lastName">Last Name :</label> 11: <input type="text" name="lastName" class="input-medium search-query" /> 12: <input type="submit" value="Retrieve" class="btn btn-primary" /> 13: </fieldset> 14: }三、顯示聯(lián)系人列表
QueryFormPartial.cshtml定義了一個以Ajax方式提交的表單,目標(biāo)Action為具有如下定義的Find,它根據(jù)指定的First Name和Last Name篩選匹配的聯(lián)系人列表,并將其呈現(xiàn)在一個名為ContactListPartial的View中。
1: public class HomeController : Controller 2: { 3: //其他成員 4: public ActionResult Find(string firstName = "", string lastName = "") 5: { 6: var result = from contact in contacts 7: where (string.IsNullOrEmpty(firstName) || contact.FirstName.ToLower().Contains(firstName.ToLower())) 8: &&(string.IsNullOrEmpty(lastName) || contact.LastName.ToLower().Contains(lastName.ToLower())) 9: orderby contact.Id 10: select contact; 11: return View("ContactListPartial",result.ToArray()); 12: } 13: }如下所示的ContactListPartial.cshtml的定義,這是一個Model類型為IEnumerable<Contact>的強(qiáng)類型View,它以表格的形式將聯(lián)系人列表呈現(xiàn)出來。
1: @model IEnumerable<Contact> 2: @{ 3: Layout = null; 4: } 5: <table class="table table-striped table-bordered"> 6: <thead> 7: <tr> 8: <th>ID</th> 9: <th>First Name</th> 10: <th>Last Name</th> 11: <th>Email Address</th> 12: <th>Phone No.</th> 13: </tr> 14: </thead> 15: <tbody> 16: @foreach (var contact in Model) 17: { 18: <tr> 19: <td>@Ajax.ActionLink(contact.Id, "Update", new { contactId = contact.Id }, new AjaxOptions { OnSuccess = "showDialog" , HttpMethod="GET"})</td> 20: <td>@contact.FirstName</td> 21: <td>@contact.LastName</td> 22: <td>@contact.EmailAddress</td> 23: <td>@contact.PhoneNo</td> 24: </tr> 25: } 26: </tbody> 27: </table>從QueryFormPartial.cshtml的定義可以看到,表單成功提交之后會調(diào)用一個名為renderCustomerList的JavaScript函數(shù)(@using (Ajax.BeginForm("Find", new AjaxOptions { OnSuccess = "renderCustomerList" }))),它以如下的方式定義在Index.cshtml中。從定義了看出,它將獲取的數(shù)據(jù)(實(shí)際上ContactListPartial這個View最終的HTML)作為contactList這個<div>的HTML。
1: <html> 2: <head> 3: <script type="text/javascript"> 1:? 2: function renderCustomerList(data) { 3: $("#contactList").html(data); 4: } 5: </script> 4: </head> 5: </html>四、彈出“修改聯(lián)系人”對話框
從ContactListPartial.cshtml的定義可以看到聯(lián)系人ID以一個鏈接的方式呈現(xiàn)出來,點(diǎn)擊該鏈接會以Ajax的方式訪問Action方法Update,當(dāng)前聯(lián)系人ID會作為請求的參數(shù)(<td>@Ajax.ActionLink(contact.Id, "Update", new { contactId = contact.Id }, new AjaxOptions { OnSuccess = "showDialog" , HttpMethod="GET"})</td>)。如下所示的是Action方法Update的定義,它根據(jù)指定的ID獲取對應(yīng)的聯(lián)系人,并將其呈現(xiàn)在一個名為ContactPartial 的View中。
1: public class HomeController : Controller 2: { 3: //其他成員 4: [HttpGet] 5: public ActionResult Update(string contactId) 6: { 7: Contact contact = contacts.First(c => c.Id == contactId); 8: return View("ContactPartial", contact); 9: } 10: }如下所示的ContactPartial.cshtml的定義,這是一個Model類型為Contact的強(qiáng)類型View,它將聯(lián)系人信息呈現(xiàn)在一個表單中。
1: @model Contact 2: @{ 3: Layout = null; 4: } 5: @using(Ajax.BeginForm("Update", null, new AjaxOptions { HttpMethod = "Post", OnSuccess = "reLoad" }, new { @class = "form-horizontal" })) 6: { 7: <div class="modal-header"> 8: <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> 9: <h3>Contact Information</h3> 10: </div> 11: <div class="modal-body"> 12: <div class="control-group"> 13: @Html.HiddenFor(model=>model.Id) 14: @Html.LabelFor(model=>model.FirstName,new{@class="control-label"}) 15: <div class="controls"> 16: @Html.EditorFor(model => model.FirstName) 17: @Html.ValidationMessageFor(model => model.FirstName) 18: </div> 19: </div> 20: <div class="control-group"> 21: @Html.LabelFor(model=>model.LastName,new{@class="control-label"}) 22: <div class="controls"> 23: @Html.EditorFor(model => model.LastName) 24: @Html.ValidationMessageFor(model => model.LastName) 25: </div> 26: </div> 27: <div class="control-group"> 28: @Html.LabelFor(model => model.EmailAddress, new { @class = "control-label" }) 29: <div class="controls"> 30: @Html.EditorFor(model => model.EmailAddress) 31: @Html.ValidationMessageFor(model => model.EmailAddress) 32: </div> 33: </div> 34: <div class="control-group"> 35: @Html.LabelFor(model => model.PhoneNo, new { @class = "control-label" }) 36: <div class="controls"> 37: @Html.EditorFor(model => model.PhoneNo) 38: @Html.ValidationMessageFor(model => model.PhoneNo) 39: </div> 40: </div> 41: </div> 42: <div class="modal-footer"> 43: <a href="#" class="btn" data-dismiss="modal">Close</a> 44: <input type="submit" class="btn btn-primary" value="Save" /> 45: </div> 46: }聯(lián)系人編譯窗口的彈出最終通過調(diào)用JavaScript函數(shù)showDialog實(shí)現(xiàn)(<td>@Ajax.ActionLink(contact.Id, "Update", new { contactId = contact.Id }, new AjaxOptions { OnSuccess = "showDialog" , HttpMethod="GET"})</td>),具體定義如下所示。它將獲取到的數(shù)據(jù)(實(shí)際上是ContactPartial這個View最終的HTML)作為第三個<div>的HTML,并按照Bootstrap的方式以模態(tài)對話框的形式將其呈現(xiàn)出來。至于中間的兩行代碼,在于解決動態(tài)添加表單無法實(shí)施驗(yàn)證的問題。
1: <html> 2: <head> 3: <script type="text/javascript"> 1: 2: function showDialog(data) { 3: $("#contactDialog").html(data); 4: $("#contactDialog form") 5: .removeData("validator") 6: .removeData("unobtrusiveValidation"); 7: $.validator.unobtrusive.parse($("#contactDialog form")); 8: $("#contactDialog").modal(); 9: } 10: </script> 4: </head> 5: </html>五、聯(lián)系人信息的最終修改
通過ContactPartial.cshtml的定義可以看出編輯聯(lián)系人表單最終以POST的方式提交到HomeController的Action方法Update(@using(Ajax.BeginForm("Update", null, new AjaxOptions { HttpMethod = "Post", OnSuccess = "reLoad" }, new { @class = "form-horizontal" }))),該Action方法具有如下的定義。它在完成修改之后,返回字符串“OK”表明聯(lián)系人修改成功。
1: public class HomeController : Controller 2: { 3: //其他成員 4: [HttpPost] 5: public string Update(Contact contact) 6: { 7: contacts.Remove(contacts.First(c=>c.Id == contact.Id)); 8: contacts.Add(contact); 9: return "OK"; 10: } 11: }聯(lián)系人修改表單提交后關(guān)閉當(dāng)前窗口并加載新的數(shù)據(jù)通過具有如下定義JavaScript函數(shù)Reload實(shí)現(xiàn)(@using(Ajax.BeginForm("Update", null, new AjaxOptions { HttpMethod = "Post", OnSuccess = "reLoad" }, new { @class = "form-horizontal" }))),該函數(shù)依然定義在Index.cshtml中。
1: <html> 2: <head> 3: <script type="text/javascript"> 1:? 2: function reLoad(data) { 3: if (data == "OK") { 4: $("#contactDialog").modal("hide"); 5: $(".form-search form").submit(); 6: } 7: } 8: </script> 4: </head> 5: </html>作者:蔣金楠
微信公眾賬號:大內(nèi)老A
微博:www.weibo.com/artech
如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術(shù)資料,可以掃描左邊二維碼(或者長按識別二維碼)關(guān)注個人公眾號(原來公眾帳號蔣金楠的自媒體將會停用)。
本文版權(quán)歸作者和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利。 原文鏈接
總結(jié)
以上是生活随笔為你收集整理的[ASP.NET MVC] 利用动态注入HTML的方式来设计复杂页面的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我的第一个 Mono for Andro
- 下一篇: [转]MD5(1)-安全性与原理