ASP.NET MVC 允許開發(fā)者創(chuàng)建自定義的 HTML Helpers,不管是使用靜態(tài)方法還是擴(kuò)展方法。一個(gè)HTML Helper 本質(zhì)上其實(shí)是輸出一段 HTML 字符串。 HTML Helpers 能讓我們在多個(gè)頁面上公用同一段 HTML 標(biāo)記,這樣不僅提高了穩(wěn)定性也便于開發(fā)者去維護(hù)。當(dāng)然對于這些可重用的代碼,開發(fā)者也方便對他們進(jìn)行單元測試。所以,創(chuàng)建 ASP.NET MVC Bootstrap Helpers 是及其有必要的。
ASP.NET MVC 內(nèi)置了若干標(biāo)準(zhǔn) HTML Helpers,通過 @ HTML
來調(diào)用這些方法在視圖引擎中解析、渲染輸出 HTML 內(nèi)容,這允許開發(fā)者在多個(gè)視圖中重用公共的方法。
舉個(gè)例子,以下代碼產(chǎn)生一個(gè) type 等于 text 的 Input ,并且其 id 和 name 都等于 CustomerName,其 Value 等于 Northwind Traders:
@ Html.TextBox("CustomerName","Northwind Traders");
大多數(shù)內(nèi)置的 HTML helpers 提供傳入匿名類型為元素產(chǎn)生指定 HTML 屬性的選項(xiàng),對上述的 @ HTML.TextBox方法稍作修改,通過傳入匿名類型設(shè)置輸出元素的 style 屬性:
@Html.TextBox("CustomerName","Northwind Traders", new { style="background-color:Blue;" })
因?yàn)?Bootstrap 提供了大量不同的組件,所以創(chuàng)建 Bootstrap helpers 可以在多個(gè)視圖上快速使用這些組件。在 ASP.NET MVC 中最簡單創(chuàng)建 Bootstrap helpers 是通過 @helper 語法來實(shí)現(xiàn)。一個(gè)自定義的 helper 可以包含任何 HTML 標(biāo)記甚至 Razor 標(biāo)記,你可以通過如下步驟來創(chuàng)建:
在項(xiàng)目的根目錄創(chuàng)建文件夾 App_Code
在 App_Code 文件夾中新建 BootstrapHelpers.cshtml 文件并加入如下代碼
@helper PrimaryButtonSmall(string id,string caption)
{
<button id="@id" type="button" class="btn btn-primary btn-sm">@caption</button>
}
上述代碼使用 @helper 創(chuàng)建了一個(gè)新的名為 PrimaryButtonSmall helper,它接受 2個(gè)參數(shù),分別是 Id 和 caption。其中,它產(chǎn)生一個(gè) Button 類型的 HTML 標(biāo)記并設(shè)置了 Bootstrap 的樣式。
注意:任何自定義的 helpers 必須存在 App_Code 文件夾中,這樣才能被 ASP.NET MVC 視圖識別。
http://wiki.jikexueyuan.com/project/think-in-asp-net-mvc/images/Chapter5/2.png" alt="" />
當(dāng)然,為了讓我們的 helper 更加通用性,比如指定大小、樣式等,對上述稍作如下修改,增加傳入的參數(shù):
@helper Button(string style, string size, string caption, string id)
{
<button id="@id" type="button" class="btn btn-@style btn-@size">@caption </button>
}
現(xiàn)在我們可以這樣去使用:
@BootstrapHelpers.Button("danger","lg","危險(xiǎn)","btnDanger")
它將產(chǎn)生如下樣式的按鈕:
http://wiki.jikexueyuan.com/project/think-in-asp-net-mvc/images/Chapter5/1.png" alt="" />
不過,這種方式的 helper 唯一的不足是你需要"hard code"傳入樣式和尺寸,這可能需要你非常熟悉Bootstrap 的樣式。
通過靜態(tài)方法同樣也能快速方便的創(chuàng)建自定義 Bootstrap helpers,同樣它也是返回了 HTML 標(biāo)記,要?jiǎng)?chuàng)建靜態(tài)方法,你可以按照如下步驟來實(shí)現(xiàn):
1.添加命了 Helpers 的文件夾
2.創(chuàng)建如下枚舉類
public class ButtonHelper
{
public static MvcHtmlString Button(string caption, Enums.ButtonStyle style, Enums.ButtonSize size)
{
if (size != Enums.ButtonSize.Normal)
{
return new MvcHtmlString(string.Format("<button type=\"button\" class=\"btn btn-{0} btn-{1}\">{2}</button>", style.ToString().ToLower(), ToBootstrapSize(size), caption));
}
return new MvcHtmlString(string.Format("<button type=\"button\" class=\"btn btn-{0}\">{1}</button>", style.ToString().ToLower(), caption));
}
private static string ToBootstrapSize(Enums.ButtonSize size)
{
string bootstrapSize = string.Empty;
switch (size)
{
case Enums.ButtonSize.Large:
bootstrapSize = "lg";
break;
case Enums.ButtonSize.Small:
bootstrapSize = "sm";
break;
case Enums.ButtonSize.ExtraSmall:
bootstrapSize = "xs";
break;
}
return bootstrapSize;
}
}
Button 方法返回了一個(gè) MvcHtmlString 對象,它代表了編碼過后的 HTML 字符。
1.通過使用靜態(tài)方法來調(diào)用:
@ButtonHelper.Button("危險(xiǎn)", Enums.ButtonStyle.Danger, Enums.ButtonSize.Large)
你可以和之前的"hard code"寫法進(jìn)行比較,盡管他們產(chǎn)生相同的結(jié)果:
@BootstrapHelpers.Button("danger","lg","危險(xiǎn)","btnDanger")
內(nèi)置的 ASP.NET MVC helper(@HTML)是基于擴(kuò)展方法的,我們可以再對上述的靜態(tài)方法進(jìn)行升級——使用擴(kuò)展方法來創(chuàng)建 Bootstrap helpers。
1.在 Helpers 文件夾下創(chuàng)建 ButtonExtensions 類 2.修改 ButtonExtensions為Static 類型 3.修改 Namespace為System.Web.Mvc.Html,這樣方便 @HTML 調(diào)用擴(kuò)展方法 4.添加擴(kuò)展方法,返回 MvcHtmlString
public static MvcHtmlString BootstrapButton(this HtmlHelper helper, string caption, Enums.ButtonStyle style, Enums.ButtonSize size)
{
if (size != Enums.ButtonSize.Normal)
{
return new MvcHtmlString(string.Format("<button type=\"button\" class=\"btn btn-{0} btn-{1}\">{2}</button>", style.ToString().ToLower(), ToBootstrapSize(size), caption));
}
return new MvcHtmlString(string.Format("<button type=\"button\" class=\"btn btn-{0}\">{1}</button>", style.ToString().ToLower(), caption));
` }`
因?yàn)?BootstrapButton 方法是擴(kuò)展方法,通過如下方式去調(diào)用:
@Html.BootstrapButton("很危險(xiǎn)",Enums.ButtonStyle.Danger,Enums.ButtonSize.Large)
寫法雖不同,但返回的結(jié)果都是一致的。
Fluent Interface(參考:http://martinfowler.com/bliki/FluentInterface.html)用于軟件開發(fā)實(shí)現(xiàn)了一種面向?qū)ο蟮?/a> API,以這種方式,它提供了更多的可讀性代碼,易于開發(fā)人員理解。通常通過鏈?zhǔn)骄幊虂韺?shí)現(xiàn)。
舉個(gè)例子,我們將創(chuàng)建一個(gè) HTML helper 來產(chǎn)生一個(gè)可關(guān)閉的警告框,使用 Fluent Interface 可以這樣來調(diào)用:
@Html.Alert("警告").Warning().Dismissible()
所以要?jiǎng)?chuàng)建 Fluent helpers,需要實(shí)現(xiàn)如下步驟:
1.創(chuàng)建 IFluentAlert 實(shí)現(xiàn) IHtmlString 接口,這是非常重要的一步,對于 ASP.NET MVC Razor 視圖引擎,如果 @ 之后返回的類型實(shí)現(xiàn)了 IHtmlString 接口,那么視圖引擎會(huì)自動(dòng)調(diào)用 ToHtmlString() 方法,返回實(shí)際的 HTML 標(biāo)記。
public interface IAlertFluent : IHtmlString
{
IAlertFluent Dismissible(bool canDismiss = true);
}
2.創(chuàng)建 IAlert 實(shí)現(xiàn) IFluentAlert 接口
public interface IAlert : IAlertFluent
{
IAlertFluent Danger();
IAlertFluent Info();
IAlertFluent Success();
IAlertFluent Warning();
}
3.創(chuàng)建 Alert 繼承 IAlert 接口
public class Alert : IAlert
{
private Enums.AlertStyle _style;
private bool _dismissible;
private string _message;
public Alert(string message)
{
_message = message;
}
public IAlertFluent Danger()
{
_style = Enums.AlertStyle.Danger;
return new AlertFluent(this);
}
public IAlertFluent Info()
{
_style = Enums.AlertStyle.Info;
return new AlertFluent(this);
}
public IAlertFluent Success()
{
_style = Enums.AlertStyle.Success;
return new AlertFluent(this);
}
public IAlertFluent Warning()
{
_style = Enums.AlertStyle.Warning;
return new AlertFluent(this);
}
public IAlertFluent Dismissible(bool canDismiss = true)
{
this._dismissible = canDismiss;
return new AlertFluent(this);
}
public string ToHtmlString()
{
var alertDiv = new TagBuilder("div");
alertDiv.AddCssClass("alert");
alertDiv.AddCssClass("alert-" + _style.ToString().ToLower());
alertDiv.InnerHtml = _message;
if (_dismissible)
{
alertDiv.AddCssClass("alert-dismissable");
alertDiv.InnerHtml += AddCloseButton();
}
return alertDiv.ToString();
}
private static TagBuilder AddCloseButton()
{
var closeButton = new TagBuilder("button");
closeButton.AddCssClass("close");
closeButton.Attributes.Add("data-dismiss", "alert");
closeButton.InnerHtml = "×";
return closeButton;
}
}
上述代碼中,通過 TagBuilder 可以快速的創(chuàng)建 HTML 元素。
4.創(chuàng)建 AlertFluent 繼承 IAlertFluent
public class AlertFluent : IAlertFluent
{
private readonly Alert _parent;
public AlertFluent(Alert parent)
{
_parent = parent;
}
public IAlertFluent Dismissible(bool canDismiss = true)
{
return _parent.Dismissible(canDismiss);
}
public string ToHtmlString()
{
return _parent.ToHtmlString();
}
}
通過構(gòu)建這種 Fluent API,我們可以鏈?zhǔn)降娜?chuàng)建 Bootstrap 組件,這對于不熟悉 Bootstrap Framework 的人來說是非常方便的,我們可以使用 @HTML.Alert("Title").Danger().Dismissible() 來創(chuàng)建如下風(fēng)格的警告框:
http://wiki.jikexueyuan.com/project/think-in-asp-net-mvc/images/Chapter5/3.png" alt="" />
在 ASP.NET MVC 中,內(nèi)置的 @HTML.BeginForm()
helper 就是一個(gè)自動(dòng)閉合的 helper。當(dāng)然我們也能自定義自動(dòng)閉合的 helpers,只要實(shí)現(xiàn) IDisposable 接口即可。使用 IDisposable 接口,當(dāng)對象 Dispose 時(shí)我們輸出元素的閉合標(biāo)記,具體按照如下步驟:
1.所以在 Helpers 文件夾下創(chuàng)建一個(gè)名為 Panel 的文件夾 2.添加 Panel,并實(shí)現(xiàn) IDisposable 接口
public class Panel : IDisposable
{
private readonly TextWriter _writer;
public Panel(HtmlHelper helper, string title, Enums.PanelStyle style = Enums.PanelStyle.Default)
{
_writer = helper.ViewContext.Writer;
var panelDiv = new TagBuilder("div");
panelDiv.AddCssClass("panel-" + style.ToString().ToLower());
panelDiv.AddCssClass("panel");
var panelHeadingDiv = new TagBuilder("div");
panelHeadingDiv.AddCssClass("panel-heading");
var heading3Div = new TagBuilder("h3");
heading3Div.AddCssClass("panel-title");
heading3Div.SetInnerText(title);
var panelBodyDiv = new TagBuilder("div");
panelBodyDiv.AddCssClass("panel-body");
panelHeadingDiv.InnerHtml = heading3Div.ToString();
string html = string.Format("{0}{1}{2}", panelDiv.ToString(TagRenderMode.StartTag), panelHeadingDiv, panelBodyDiv.ToString(TagRenderMode.StartTag));
_writer.Write(html);
}
public void Dispose()
{
_writer.Write("</div></div>");
}
}
上述代碼中利用Write屬性可以在當(dāng)前視圖中輸出HTML標(biāo)記,并在Dispose方法里輸出2個(gè)閉合的div標(biāo)簽。
注意,我們重寫了TagBuilder的ToString()方法,只讓它生成div元素的開始標(biāo)簽。
3.在View中使用自動(dòng)閉合的helpers
@using (Html.Panel("Title", Enums.PanelStyle.Success))
{
<p>這是自動(dòng)閉合的Helpers</p>
<p>panel..</p>
}
產(chǎn)生的結(jié)果如下:
http://wiki.jikexueyuan.com/project/think-in-asp-net-mvc/images/Chapter5/4.png" alt="" />
在這篇博客中,為了減少書寫HTML標(biāo)記,我們創(chuàng)建了若干Bootstrap helpers來實(shí)現(xiàn)。這些helpers的意義在于能讓不了解Bootstrap Framework的人也能快速上手Bootstrap。