C# 封裝HtmlHelper組件:BootstrapHelper
前言:之前學(xué)習(xí)過很多的Bootstrap組件,博主就在腦海里構(gòu)思:是否可以封裝一套自己Bootstrap組件庫(kù)呢。再加上看到MVC的Razor語法里面直接通過后臺(tái)方法輸出前端控件的方式,于是打算仿照HtmlHelper封裝一套BootstrapHelper,今天只是一個(gè)開頭,講述下如何封裝自己的Html組件,以后慢慢完善。
一、揭開HtmlHelper的“面紗”
經(jīng)常使用Razor寫法的園友都知道,在cshtml里面,我們可以通過后臺(tái)的方法輸出成前端的html組件,比如我們隨便看兩個(gè)例子:
輸出成Html之后
博主的好奇心又來了,它是怎么做到的呢?于是將Html對(duì)象以及Label()方法轉(zhuǎn)到定義
由此可以看出Html對(duì)象是HtmlHelper類型的一個(gè)實(shí)例,而Label()方法則是HtmlHelper類型的一個(gè)擴(kuò)展方法,所以就可以直接通過Html.Label()這種方式直接調(diào)用。
既然我們想要封裝自己的HtmlHelper,那么我們就必須要了解Label()方法里面是如何實(shí)現(xiàn)的,我們偉大的Reflector又派上用場(chǎng)了。我們來反編譯System.Web.MVC.dll看看。找到LabelExtensions這個(gè)類
經(jīng)過一系列的轉(zhuǎn)到定義,我們找到最終的方法
同樣,我們找到TextBox()最終定義的方法
喲西,原來就是TagBuilder這個(gè)一個(gè)小東西,讓人覺得神奇得不要不要的。所以有時(shí)我們需要敢于反編譯,或許看似高級(jí)的背后其實(shí)很簡(jiǎn)單呢~~
二、BootstrapHelper組件封裝準(zhǔn)備
1、定義BootstrapHelper
有了以上的基礎(chǔ)做準(zhǔn)備,接下來就是具體的實(shí)現(xiàn)了,我們新建了一個(gè)空的MVC項(xiàng)目,添加如下文件。
編譯發(fā)現(xiàn)報(bào)錯(cuò)如下
將HtmlHelper轉(zhuǎn)到定義發(fā)現(xiàn)它有兩個(gè)構(gòu)造函數(shù),分別有兩個(gè)、三個(gè)參數(shù)
那么,我們的BootstrapHelper也定義兩個(gè)構(gòu)造函數(shù),于是代碼變成這樣:
namespace Extensions { public class BootstrapHelper : System.Web.Mvc.HtmlHelper { /// <summary> /// 使用指定的視圖上下文和視圖數(shù)據(jù)容器來初始化 BootstrapHelper 類的新實(shí)例。 /// </summary> /// <param name="viewContext">視圖上下文</param> /// <param name="viewDataContainer">視圖數(shù)據(jù)容器</param> public BootstrapHelper(ViewContext viewContext, IViewDataContainer viewDataContainer) : base(viewContext, viewDataContainer) { } /// <summary> /// 使用指定的視圖上下文、視圖數(shù)據(jù)容器和路由集合來初始化 BootstrapHelper 類的新實(shí)例。 /// </summary> /// <param name="viewContext">視圖上下文</param> /// <param name="viewDataContainer">視圖數(shù)據(jù)容器</param> /// <param name="routeCollection">路由集合</param> public BootstrapHelper(ViewContext viewContext, IViewDataContainer viewDataContainer, RouteCollection routeCollection) : base(viewContext, viewDataContainer, routeCollection) { } } }
這樣通過子類復(fù)用父類的構(gòu)造函數(shù)的方式即可解決以上問題。編譯通過!
2、定義LabelExtensions
上面我們研究過HtmlHelper,在HtmlHelper里面,不同的html組件定義了不同的Extension(擴(kuò)展),下面我們就以最簡(jiǎn)單的Label標(biāo)簽為例定義我們BootstrapHelper里面的Label標(biāo)簽。
同樣,在Extensions文件夾里面我們新建了一個(gè)文件LabelExtensions.cs,用于定義Label標(biāo)簽的擴(kuò)展,它里面的基本實(shí)現(xiàn)如下:
namespace Extensions { public static class LabelExtensions { /// <summary> /// 通過使用指定的 HTML 幫助器和窗體字段的名稱,返回Label標(biāo)簽 /// </summary> /// <param name="html">擴(kuò)展方法實(shí)例</param> /// <param name="id">標(biāo)簽的id</param> /// <param name="content">標(biāo)簽的內(nèi)容</param> /// <param name="cssClass">標(biāo)簽的class樣式</param> /// <param name="htmlAttributes">標(biāo)簽的額外屬性(如果屬性里面含有“-”,請(qǐng)用“_”代替)</param> /// <returns>label標(biāo)簽的html字符串</returns> public static MvcHtmlString Label(this BootstrapHelper html, string id, string content, string cssClass, object htmlAttributes) { //定義標(biāo)簽的名稱 TagBuilder tag = new TagBuilder("label"); //給標(biāo)簽增加額外的屬性 IDictionary<string, object> attributes = BootstrapHelper.AnonymousObjectToHtmlAttributes(htmlAttributes); if (!string.IsNullOrEmpty(id)) { attributes.Add("id", id); } if (!string.IsNullOrEmpty(cssClass)) { //給標(biāo)簽增加樣式 tag.AddCssClass(cssClass); } //給標(biāo)簽增加文本 tag.SetInnerText(content); tag.AddCssClass("control-label"); tag.MergeAttributes(attributes); return MvcHtmlString.Create(tag.ToString()); } } }
我們暫且只定義一個(gè)方法,其他的重載我們很好擴(kuò)展,這里給所有的BootstrapHelper里面的Label標(biāo)簽統(tǒng)一添加了“control-label”樣式,當(dāng)然,如果你的項(xiàng)目里面的label標(biāo)簽定義了自己的樣式,那么這里改成你需要的樣式即可。以上代碼都比較基礎(chǔ),這里就不一一講解。
3、定義BootstrapWebViewPage
以上定義了BootstrapHelper和LabelExtensions,準(zhǔn)備工作是做好了,但是還少一個(gè)對(duì)象,比如我們?cè)赾shtml頁面里面@Html.Label("姓名")這樣寫,Html變量是一個(gè)HtmlHelper類型的對(duì)象,那么,如果我們需要使用類似@Bootstrap.Label()這種寫法,以此類推,Bootstrap變量應(yīng)該也是一個(gè)BootstrapHelper類型的對(duì)象,那么如果我們要這么用,必須要先定義一個(gè)Bootstrap變量,這個(gè)變量到底在哪里定義呢。于是博主思考,Html變量是定義在哪里的呢?再次轉(zhuǎn)到定義
原來是在WebViewPage這個(gè)類的子類中,同樣,我們?cè)贓xtensions文件夾里面也新建一個(gè)WebViewPage的子類BootstrapWebViewPage,實(shí)現(xiàn)代碼如下:
namespace Extensions { public abstract class BootstrapWebViewPage<T> : System.Web.Mvc.WebViewPage<T> { //在cshtml頁面里面使用的變量 public BootstrapHelper Bootstrap { get; set; } /// <summary> /// 初始化Bootstrap對(duì)象 /// </summary> public override void InitHelpers() { base.InitHelpers(); Bootstrap = new BootstrapHelper(ViewContext, this); } public override void Execute() { //throw new NotImplementedException(); } } }
至于這里的泛型,我們以后再來做講解,這里先不做過多糾結(jié)
4、實(shí)踐
有了以上三步,所有需要的方法和變量都齊全了,貌似已經(jīng)“萬事俱備只欠東風(fēng)”了,是不是這樣呢?我們來試一把
編譯,將Index.cshtml頁面關(guān)閉重新打開,發(fā)現(xiàn)仍然找不到Bootstrap對(duì)象
怎么回事呢,Html是可以找到的,那Bootstrap變量去哪里了呢。。。
經(jīng)過一番查找資料,發(fā)現(xiàn)在View文件夾里面有一個(gè)web.config文件(之前一直沒怎么在意這個(gè)東西,現(xiàn)在想想里面還是有學(xué)問的哦),里面有一個(gè)節(jié)點(diǎn)system.web.webPages.razor下面有一個(gè)pages節(jié)點(diǎn),默認(rèn)是這樣的:
<system.web.webPages.razor> <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.2.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> <pages pageBaseType="System.Web.Mvc.WebViewPage"> <namespaces> <add namespace="System.Web.Mvc" /> <add namespace="System.Web.Mvc.Ajax" /> <add namespace="System.Web.Mvc.Html" /> <add namespace="System.Web.Routing" /> <add namespace="BootstrapHelper" /> </namespaces> </pages> </system.web.webPages.razor>
我們將pages節(jié)點(diǎn)的pageBaseType改成我們的WebViewPage
<system.web.webPages.razor> <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.2.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> <pages pageBaseType="Extensions.BootstrapWebViewPage"> <namespaces> <add namespace="System.Web.Mvc" /> <add namespace="System.Web.Mvc.Ajax" /> <add namespace="System.Web.Mvc.Html" /> <add namespace="System.Web.Routing" /> <add namespace="BootstrapHelper" /> </namespaces> </pages> </system.web.webPages.razor>
然后編譯,重新打開Index.cshtml。
OK,可以找到Bootstrap對(duì)象了。我們將Index.cshtml里面寫入如下內(nèi)容:
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Index</title> </head> <body> <div> @Html.Label("姓名") @Html.TextBox("a", "Jim") @Bootstrap.Label(null, "Bootstrap Label標(biāo)簽", null, null) </div> </body> </html>
運(yùn)行看看效果:
怎么還是報(bào)錯(cuò)呢?這個(gè)問題應(yīng)該不難理解,因?yàn)樵趓azor里面使用@調(diào)用后臺(tái)變量和方法的時(shí)候也存在命名空間的概念,這個(gè)命名空間在哪里引用呢,還是在View文件夾里面的web.config里面,在system.web.webPages.razor節(jié)點(diǎn)下面存在namespace的節(jié)點(diǎn),我們將自定義的Label()擴(kuò)展方法所在的命名空間加進(jìn)去即可。于是配置變成這樣:
<system.web.webPages.razor> <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.2.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> <pages pageBaseType="Extensions.BootstrapWebViewPage"> <namespaces> <add namespace="System.Web.Mvc" /> <add namespace="System.Web.Mvc.Ajax" /> <add namespace="System.Web.Mvc.Html" /> <add namespace="System.Web.Routing" /> <add namespace="BootstrapHelper" /> <add namespace="Extensions"/> </namespaces> </pages> </system.web.webPages.razor>
再次運(yùn)行
三、BootstrapHelper組件完善
通過上面一系列發(fā)現(xiàn)坑、填坑的經(jīng)歷,一個(gè)最最簡(jiǎn)單的BootstrapHelper組件已經(jīng)基本可用。我們將LabelExtensions簡(jiǎn)單完善下:
namespace Extensions { public static class LabelExtensions { public static MvcHtmlString Label(this BootstrapHelper html, string id) { return Label(html, id, null, null, null); } public static MvcHtmlString Label(this BootstrapHelper html, string content) { return Label(html, null, content, null, null); } public static MvcHtmlString Label(this BootstrapHelper html, string id, string content) { return Label(html, id, content, null, null); } public static MvcHtmlString Label(this BootstrapHelper html, string id, string content, object htmlAttributes) { return Label(html, id, content, null, htmlAttributes); } /// <summary> /// 通過使用指定的 HTML 幫助器和窗體字段的名稱,返回Label標(biāo)簽 /// </summary> /// <param name="html">擴(kuò)展方法實(shí)例</param> /// <param name="id">標(biāo)簽的id</param> /// <param name="content">標(biāo)簽的內(nèi)容</param> /// <param name="cssClass">標(biāo)簽的class樣式</param> /// <param name="htmlAttributes">標(biāo)簽的額外屬性(如果屬性里面含有“-”,請(qǐng)用“_”代替)</param> /// <returns>label標(biāo)簽的html字符串</returns> public static MvcHtmlString Label(this BootstrapHelper html, string id, string content, string cssClass, object htmlAttributes) { //定義標(biāo)簽的名稱 TagBuilder tag = new TagBuilder("label"); //給標(biāo)簽增加額外的屬性 IDictionary<string, object> attributes = BootstrapHelper.AnonymousObjectToHtmlAttributes(htmlAttributes); if (!string.IsNullOrEmpty(id)) { attributes.Add("id", id); } if (!string.IsNullOrEmpty(cssClass)) { //給標(biāo)簽增加樣式 tag.AddCssClass(cssClass); } //給標(biāo)簽增加文本 tag.SetInnerText(content); tag.AddCssClass("control-label"); tag.MergeAttributes(attributes); return MvcHtmlString.Create(tag.ToString()); } } }
呵呵,是不是有模有樣~~可能又有人要說博主“山寨”了,呵呵,不管山寨不山寨,你覺得爽就行。
四、總結(jié)
這篇先到這里,一路填坑,基本功能總算可用。還有一些需要完善的地方,比如泛型,比如lamada表達(dá)式等等,來日方長(zhǎng),博主有時(shí)間完善下。還有最基礎(chǔ)的一些表單控件,我們都需要封裝,這個(gè)估計(jì)還有點(diǎn)工作量,只能慢慢來完善了,等完善都一定的程度會(huì)開源在git上,希望自己能夠堅(jiān)持下去!如果你覺得本文對(duì)你有幫助,請(qǐng)幫忙推薦下,您的推薦是博主堅(jiān)持完善的動(dòng)力。
以上所述是小編給大家介紹的C# 封裝HtmlHelper組件之BootstrapHelper ,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
- MVC HtmlHelper擴(kuò)展類(PagingHelper)實(shí)現(xiàn)分頁功能
- 一步一步封裝自己的HtmlHelper組件BootstrapHelper(三)
- 一步一步封裝自己的HtmlHelper組件BootstrapHelper(二)
- ASP.NET MVC HtmlHelper如何擴(kuò)展
- ASP.NET MVC4 HtmlHelper擴(kuò)展類,實(shí)現(xiàn)分頁功能
- ASP.NET MVC中HtmlHelper控件7個(gè)大類中各個(gè)控件使用詳解
- asp.net 圖片驗(yàn)證碼的HtmlHelper
- ASP.NET MVC擴(kuò)展HtmlHelper方法
相關(guān)文章
WPF中使用CallerMemberName簡(jiǎn)化InotifyPropertyChanged的實(shí)現(xiàn)
這篇文章介紹了WPF中使用CallerMemberName簡(jiǎn)化InotifyPropertyChanged的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06Unity Sockect實(shí)現(xiàn)畫面實(shí)時(shí)傳輸案例原理解析
Socket是比較常用的一種通信方式,本文通過案例給大家介紹Unity Sockect實(shí)現(xiàn)畫面實(shí)時(shí)傳輸功能,感興趣的朋友一起看看吧2021-08-08