序言
ASP.NET MVC允許開發者創建自定義的HTML Helpers,不管是使用靜態方法還是擴展方法。一個HTML Helper本質上其實是輸出一段HTML字符串。
HTML Helpers能讓我們在多個頁面上公用同一段HTML標記,這樣不僅提高了穩定性也便於開發者去維護。當然對於這些可重用的代碼,開發者也方便對他們進行單元測試。所以,創建ASP.NET MVC Bootstrap Helpers是及其有必要的。
內置的HTML Helpers
ASP.NET MVC內置了若干標准HTML Helpers,通過@HTML來調用這些方法在視圖引擎中解析、渲染輸出HTML內容,這允許開發者在多個視圖中重用公共的方法。
舉個栗子,以下代碼產生一個type等於text的Input ,並且其id和name都等於CustomerName,其Value等於Northwind Traders:
-
@Html.TextBox("CustomerName","Northwind Traders");
大多數內置的HTML helpers提供傳入匿名類型為元素產生指定HTML屬性的選項,對上述的@HTML.TextBox方法稍作修改,通過傳入匿名類型設置輸出元素的style屬性:
-
@Html.TextBox("CustomerName","Northwind Traders", new { style="background-color:Blue;" })
創建自定義的Helpers
因為Bootstrap提供了大量不同的組件,所以創建Bootstrap helpers可以在多個視圖上快速使用這些組件。在ASP.NET MVC中最簡單創建Bootstrap helpers是通過@helper語法來實現。一個自定義的helper可以包含任何HTML標記甚至Razor標記,你可以通過如下步驟來創建:
- 在項目的根目錄創建文件夾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創建了一個新的名為PrimaryButtonSmall helper,它接受2個參數,分別是Id和caption。其中,它產生一個Button類型的HTML標記並設置了Bootstrap的樣式。
注意:任何自定義的helpers必須存在App_Code文件夾中,這樣才能被ASP.NET MVC視圖識別。
- 在視圖中通過 @BootstrapHelpers.PrimaryButtonSmall("btnSave","保存")來使用新創建的helper。
- 它將產生如下Bootstrap HTML元素:

當然,為了讓我們的helper更加通用性,比如指定大小、樣式等,對上述稍作如下修改,增加傳入的參數:
-
@helper Button(string style, string size, string caption, string id)
-
{
-
<button id="@id" type="button" class="btn btn-@style btn-@size">@caption </button>
-
}
現在我們可以這樣去使用:
-
@BootstrapHelpers.Button("danger","lg","危險","btnDanger")
它將產生如下樣式的按鈕:

不過,這種方式的helper唯一的不足是你需要"hard code"傳入樣式和尺寸,這可能需要你非常熟悉Bootstrap的樣式。
使用靜態方法創建Helpers
通過靜態方法同樣也能快速方便的創建自定義Bootstrap helpers,同樣它也是返回了HTML標記,要創建靜態方法,你可以按照如下步驟來實現:
- 添加命了Helpers的文件夾
- 創建如下枚舉類
-
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方法返回了一個MvcHtmlString對象,它代表了編碼過后的HTML字符。
- 通過使用靜態方法來調用:
-
@ButtonHelper.Button("危險", Enums.ButtonStyle.Danger, Enums.ButtonSize.Large)
你可以和之前的"hard code"寫法進行比較,盡管他們產生相同的結果:
-
@BootstrapHelpers.Button("danger","lg","危險","btnDanger")
使用擴展方法創建Helpers
內置的ASP.NET MVC helper(@HTML)是基於擴展方法的,我們可以再對上述的靜態方法進行升級——使用擴展方法來創建Bootstrap helpers。
- 在Helpers文件夾下創建ButtonExtensions類
- 修改ButtonExtensions為Static類型
- 修改Namespace為System.Web.Mvc.Html,這樣方便@HTML調用擴展方法
- 添加擴展方法,返回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));
-
}
因為BootstrapButton方法是擴展方法,通過如下方式去調用:
-
@Html.BootstrapButton("很危險",Enums.ButtonStyle.Danger,Enums.ButtonSize.Large)
寫法雖不同,但返回的結果都是一致的。
創建Fluent Helpers
Fluent Interface(參考:http://martinfowler.com/bliki/FluentInterface.html)用於軟件開發實現了一種面向對象的API,以這種方式,它提供了更多的可讀性代碼,易於開發人員理解。通常通過鏈式編程來實現。
舉個栗子,我們將創建一個HTML helper來產生一個可關閉的警告框,使用Fluent Interface可以這樣來調用:
-
@Html.Alert("警告").Warning().Dismissible()
所以要創建Fluent helpers,需要實現如下步驟:
- 創建IFluentAlert實現IHtmlString接口,這是非常重要的一步,對於ASP.NET MVC Razor視圖引擎,如果@之后返回的類型實現了IHtmlString接口,那么視圖引擎會自動調用ToHtmlString()方法,返回實際的HTML標記。
-
public interface IAlertFluent : IHtmlString
-
{
-
IAlertFluent Dismissible(bool canDismiss = true);
-
}
- 創建IAlert實現IFluentAlert接口
-
public interface IAlert : IAlertFluent
-
{
-
IAlertFluent Danger();
-
IAlertFluent Info();
-
IAlertFluent Success();
-
IAlertFluent Warning();
-
}
- 創建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可以快速的創建HTML元素。
- 創建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();
-
}
-
}
- 最后創建靜態方法
-
public static class AlertHelper
-
{
-
public static Alert Alert(this HtmlHelper html,string message)
-
{
-
return new Alert(message);
-
}
-
}
通過構建這種Fluent API,我們可以鏈式的去創建Bootstrap 組件,這對於不熟悉Bootstrap Framework的人來說是非常方便的,我們可以使用@HTML.Alert("Title").Danger().Dismissible()來創建如下風格的警告框:

創建自動閉合的Helpers
在ASP.NET MVC中,內置的@HTML.BeginForm() helper就是一個自動閉合的helper。當然我們也能自定義自動閉合的helpers,只要實現IDisposable接口即可。使用IDisposable接口,當對象Dispose時我們輸出元素的閉合標記,具體按照如下步驟:
- 所以在Helpers文件夾下創建一個名為Panel的文件夾
- 添加Panel,並實現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屬性可以在當前視圖中輸出HTML標記,並在Dispose方法里輸出2個閉合的<div>標簽。
注意,我們重寫了TagBuilder的ToString()方法,只讓它生成<div>元素的開始標簽。
- 在View中使用自動閉合的helpers
-
@using (Html.Panel("Title", Enums.PanelStyle.Success))
-
{
-
<p>這是自動閉合的Helpers</p>
-
<p>panel..</p>
-
}
產生的結果如下:

小結
在這篇博客中,為了減少書寫HTML標記,我們創建了若干Bootstrap helpers來實現。這些helpers的意義在於能讓不了解Bootstrap Framework的人也能快速上手Bootstrap。
