ASP.NET MVC使用Bootstrap系列(5)——创建ASP.NET MVC Bootstrap Helpers

序言

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 = "&times;"; 
 
  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。 参考代码下载

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Golang语言社区

Redis之并发写入

首先需要澄清一个事实:redis服务端是单线程处理客户端请求,也就是说客户端请求在服务端是串行化执行的,因此对服务端来说,并不存在并发问题。但业务方却存在并发操...

77270
来自专栏一直在跳坑然后爬坑

Flutter “跳转页面”(二)前言正文

写了这么多文章,有翻译文档的,有自己理解的,也不知道到底是怎么样的风格更能让人接受,希望大家能给点意见或建议。

51820
来自专栏大内老A

浅谈ASP.NET的Postback

说道ASP.NET的Postback,就得说Web Page的生命周期,但是Web Page的生命周期却不是三言两语就能够说得清楚的,所以在这里单纯站的编程的角...

24850
来自专栏技术之路

Caliburn.Micro学习笔记(二)----Actions

上一篇已经简单说了一下引导类和简单的控件绑定 我的上一个例子里的button自动匹配到ViewModel事件你一定感觉很好玩吧 今天说一下它的Actions,看...

23390
来自专栏小灰灰

Java 实现 markdown转Image

markdown 转 image 前段时间实现了长图文生成的基本功能,然后想了下能否有个进阶版,直接将markdown生成渲染后的图片呢? 思路 有不少的库...

38050
来自专栏转载gongluck的CSDN博客

vc++快速使用richedit控件

? vc++快速使用richedit控件 1)初始化//必须加,否则无法显示窗口 CXXXApp::CXXXApp()  //找到应用类 { // TOD...

49680
来自专栏张善友的专栏

Notepad2 一个很不错的记事本

有如下特性: 1、自定义语法高亮,支持HTML, XML, CSS, JavaScript, VBScript, ASP,PHP, CSS, Perl/CGI,...

27490
来自专栏偏前端工程师的驿站

JS魔法堂:再识IE的内存泄露

一、前言                               IE6~8除了不遵守W3C标准和各种诡异外,我想最让人诟病的应该是内存泄露的问题了。这阵子...

27250
来自专栏hotqin888的专栏

bootstrap table x-editable select2——带图标的选择

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hotqin888/article/det...

1.6K10
来自专栏玄魂工作室

如何将HTML字符转换为DOM节点并动态添加到文档中

将字符串动态转换为DOM节点,在开发中经常遇到,尤其在模板引擎中更是不可或缺的技术。 字符串转换为DOM节点本身并不难,本篇文章主要涉及两个主题:<br />

20820

扫码关注云+社区

领取腾讯云代金券