一步一步封装自己的HtmlHelper组件:BootstrapHelper

前言:之前学习过很多的Bootstrap组件,博主就在脑海里构思:是否可以封装一套自己Bootstrap组件库呢。再加上看到MVC的Razor语法里面直接通过后台方法输出前端控件的方式,于是打算仿照HtmlHelper封装一套BootstrapHelper,今天只是一个开头,讲述下如何封装自己的Html组件,以后慢慢完善。

本文原创地址:http://www.cnblogs.com/landeanfen/p/5729551.html

一、揭开HtmlHelper的“面纱”

经常使用Razor写法的园友都知道,在cshtml里面,我们可以通过后台的方法输出成前端的html组件,比如我们随便看两个例子:

输出成Html之后

博主的好奇心又来了,它是怎么做到的呢?于是将 Html 对象以及 Label() 方法转到定义

由此可以看出Html对象是HtmlHelper类型的一个实例,而Label()方法则是HtmlHelper类型的一个扩展方法,所以就可以直接通过Html.Label()这种方式直接调用。不熟悉C#扩展方法的园友可以看看http://www.cnblogs.com/landeanfen/p/4632467.html。

 既然我们想要封装自己的HtmlHelper,那么我们就必须要了解Label()方法里面是如何实现的,我们伟大的Reflector又派上用场了。我们来反编译System.Web.MVC.dll看看。找到LabelExtensions这个类

经过一系列的转到定义,我们找到最终的方法

同样,我们找到TextBox()最终定义的方法

哟西,原来就是TagBuilder这个一个小东西,让人觉得神奇得不要不要的。所以有时我们需要敢于反编译,或许看似高级的背后其实很简单呢~~

二、BootstrapHelper组件封装准备

1、定义BootstrapHelper

有了以上的基础做准备,接下来就是具体的实现了,我们新建了一个空的MVC项目,添加如下文件。

编译发现报错如下

将HtmlHelper转到定义发现它有两个构造函数,分别有两个、三个参数

 那么,我们的BootstrapHelper也定义两个构造函数,于是代码变成这样:

namespace Extensions
{    public class BootstrapHelper : System.Web.Mvc.HtmlHelper{        /// <summary>/// 使用指定的视图上下文和视图数据容器来初始化 
BootstrapHelper 类的新实例。        
/// </summary>/// <param name="viewContext">视图上下文</param>/// <param name="viewDataContainer">视图数据容器</param>public BootstrapHelper(ViewContext viewContext,
IViewDataContainer viewDataContainer): base(viewContext, viewDataContainer){ } /// <summary>/// 使用指定的视图上下文、视图数据容器和路由集合来初始化
       /// BootstrapHelper 类的新实例。      
      
/// </summary>/// <param name="viewContext">视图上下文</param>/// <param name="viewDataContainer">视图数据容器</param>/// <param name="routeCollection">路由集合</param>public BootstrapHelper(ViewContext viewContext,
IViewDataContainer viewDataContainer, RouteCollection routeCollection): base(viewContext, viewDataContainer, routeCollection){ }} }

这样通过子类复用父类的构造函数的方式即可解决以上问题。编译通过!

2、定义LabelExtensions

上面我们研究过HtmlHelper,在HtmlHelper里面,不同的html组件定义了不同的Extension(扩展),下面我们就以最简单的Label标签为例定义我们BootstrapHelper里面的Label标签。

同样,在Extensions文件夹里面我们新建了一个文件LabelExtensions.cs,用于定义Label标签的扩展,它里面的基本实现如下:

namespace Extensions
{   
public static class LabelExtensions{
/// <summary>/// 通过使用指定的 HTML 帮助器和窗体字段的名称,返回Label标签    
   
/// </summary>/// <param name="html">扩展方法实例</param>/// <param name="id">标签的id</param>/// <param name="content">标签的内容</param>/// <param name="cssClass">标签的class样式</param>/// <param name="htmlAttributes">标签的额外属性
(如果属性里面含有“-”,请用“_”代替)
</param>/// <returns>label标签的html字符串</returns>public static MvcHtmlString Label(this BootstrapHelper html,
string id, string content, string cssClass, object htmlAttributes){ //定义标签的名称TagBuilder tag = new TagBuilder("label");
//给标签增加额外的属性IDictionary<string, object> attributes =
BootstrapHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
if (!string.IsNullOrEmpty(id)){attributes.Add("id", id);} if (!string.IsNullOrEmpty(cssClass)){ //给标签增加样式tag.AddCssClass(cssClass);} //给标签增加文本tag.SetInnerText(content);tag.AddCssClass("control-label");tag.MergeAttributes(attributes);
return MvcHtmlString.Create(tag.ToString());}} }

我们暂且只定义一个方法,其他的重载我们很好扩展,这里给所有的BootstrapHelper里面的Label标签统一添加了“control-label”样式,当然,如果你的项目里面的label标签定义了自己的样式,那么这里改成你需要的样式即可。以上代码都比较基础,这里就不一一讲解。

3、定义BootstrapWebViewPage

以上定义了BootstrapHelper和LabelExtensions,准备工作是做好了,但是还少一个对象,比如我们在cshtml页面里面 @Html.Label("姓名") 这样写,Html变量是一个HtmlHelper类型的对象,那么,如果我们需要使用类似 @Bootstrap.Label() 这种写法,以此类推,Bootstrap变量应该也是一个BootstrapHelper类型的对象,那么如果我们要这么用,必须要先定义一个Bootstrap变量,这个变量到底在哪里定义呢。于是博主思考,Html变量是定义在哪里的呢?再次转到定义

原来是在WebViewPage这个类的子类中,同样,我们在Extensions文件夹里面也新建一个WebViewPage的子类BootstrapWebViewPage,实现代码如下:

namespace Extensions
{    
   public abstract class BootstrapWebViewPage<T> :
System.Web.Mvc.WebViewPage<T>{
//在cshtml页面里面使用的变量public BootstrapHelper Bootstrap { get; set; }
/// <summary>/// 初始化Bootstrap对象      
      
/// </summary>public override void InitHelpers(){ base.InitHelpers();Bootstrap = new BootstrapHelper(ViewContext, this);} public override void Execute(){ //throw new NotImplementedException();}} }

至于这里的泛型,我们以后再来做讲解,这里先不做过多纠结

 4、实践

 有了以上三步,所有需要的方法和变量都齐全了,貌似已经“万事俱备只欠东风”了,是不是这样呢?我们来试一把

编译,将Index.cshtml页面关闭重新打开,发现仍然找不到Bootstrap对象

怎么回事呢,Html是可以找到的,那Bootstrap变量去哪里了呢。。。

经过一番查找资料,发现在View文件夹里面有一个web.config文件(之前一直没怎么在意这个东西,现在想想里面还是有学问的哦),里面有一个节点system.web.webPages.razor下面有一个pages节点,默认是这样的:


  <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节点的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对象了。我们将Index.cshtml里面写入如下内容:

@{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标签", null, null)   
</div></body></html>


运行看看效果:

 

怎么还是报错呢?这个问题应该不难理解,因为在razor里面使用@调用后台变量和方法的时候也存在命名空间的概念,这个命名空间在哪里引用呢,还是在View文件夹里面的web.config里面,在system.web.webPages.razor节点下面存在namespace的节点,我们将自定义的Label()扩展方法所在的命名空间加进去即可。于是配置变成这样:

  <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>

再次运行

三、BootstrapHelper组件完善

通过上面一系列发现坑、填坑的经历,一个最最简单的BootstrapHelper组件已经基本可用。我们将LabelExtensions简单完善下:

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标签    
    
/// </summary>/// <param name="html">扩展方法实例</param>/// <param name="id">标签的id</param>/// <param name="content">标签的内容</param>/// <param name="cssClass">标签的class样式</param>/// <param name="htmlAttributes">标签的额外属性
       (如果属性里面含有“-”,请用“_”代替)
</param>/// <returns>label标签的html字符串</returns>public static MvcHtmlString Label(this BootstrapHelper html,
string id, string content, string cssClass, object htmlAttributes){ //定义标签的名称TagBuilder tag = new TagBuilder("label");
//给标签增加额外的属性IDictionary<string, object> attributes =
BootstrapHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
if (!string.IsNullOrEmpty(id)){attributes.Add("id", id);} if (!string.IsNullOrEmpty(cssClass)){ //给标签增加样式tag.AddCssClass(cssClass);} //给标签增加文本tag.SetInnerText(content);tag.AddCssClass("control-label");tag.MergeAttributes(attributes);
return MvcHtmlString.Create(tag.ToString());}} }

呵呵,是不是有模有样~~可能又有人要说博主“山寨”了,呵呵,不管山寨不山寨,你觉得爽就行。

四、总结

 这篇先到这里,一路填坑,基本功能总算可用。还有一些需要完善的地方,比如泛型,比如lamada表达式等等,来日方长,博主有时间完善下。还有最基础的一些表单控件,我们都需要封装,这个估计还有点工作量,只能慢慢来完善了,等完善都一定的程度会开源在git上,希望自己能够坚持下去!如果你觉得本文对你有帮助,请帮忙推荐下,您的推荐是博主坚持完善的动力。


原文地址:http://www.cnblogs.com/landeanfen/p/5729551.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/328841.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

sql server简单查询

一、插入多行数据&#xff1a;1.insert into 。。。 select 从一个表中取出数据插入另一个已存在的表2.select into 从一个表中取出数据插入一个新表中3.insert into ()unionselect 常量列表 二、简单查询1. 查询所有行和列 SELECT * FROM 表名2.查询部分列 SELECT 列列…

推荐系统常用的推荐算法

转载自 推荐系统常用的推荐算法 一、推荐系统概述和常用评价指标1.1 推荐系统的特点 在知乎搜了一下推荐系统&#xff0c;果真结果比较少&#xff0c;显得小众一些&#xff0c;然后大家对推荐系统普遍的观点是&#xff1a; (1)重要性UI>数据>算法&#xff0c;就是推荐系…

拥抱.NET Core,学习.NET Core的基础知识补遗

前言 .NET Core的新特性之一就是跨平台&#xff0c;但由于对之前框架的兼容导致编写一个.NET Core类库变得相当复杂&#xff0c;主要体现为相当多的框架目标和支持平台&#xff0c;今天我们就对.NET Core的跨平台特性进行一次梳理。 在.NET Core之前 其实早在.NET Core之前微软…

sql server模糊查询、分组

一、系统函数1。convert&#xff08;类型[length] &#xff0c;表达式[&#xff0c;样式]&#xff09;2.isnull&#xff08;表达式&#xff0c;默认值&#xff09;字符函数&#xff1a;len() 长度ltrim&#xff08;&#xff09;|rtrim&#xff08;&#xff09;去除左右空格righ…

拥抱.NET Core,如何开发一个跨平台类库

在此前的文章中详细介绍了使用.NET Core的基本知识&#xff0c;如果还没有看&#xff0c;可以先去了解“拥抱.NET Core&#xff0c;学习.NET Core的基础知识补遗”&#xff0c;以便接下来的阅读。 在本文将介绍如何配置类库项目支持不同的平台&#xff0c;并为不同的平台进行兼…

常用的推荐算法小结

转载自 常用的推荐算法小结推荐系统的必然 互联网发展到现阶段&#xff0c;信息已经不是匮乏&#xff0c;而是爆炸。所以良好的用户体验就是把用户喜欢的&#xff0c;感兴趣的从大量的数据中筛选出来&#xff0c;再呈现给用户&#xff0c;实现千人千面的效果。 所以推荐系统的…

.NET 4.6.2正式发布带来众多特性

虽然大多数人的注意力都集中在.NET Core上&#xff0c;但与原来的.NET Framework相关的工作还在继续。.NET Framework 4.6.2正式版已于近日发布&#xff0c;其重点是安全和WinForms/WPF/ASP.NET/WCF相关的特性,英文博客文章https://blogs.msdn.microsoft.com/dotnet/2016/08/02…

推荐算法-关联分析(关联规则)

转载自 推荐算法-关联分析&#xff08;关联规则&#xff09;关联分析又称关联挖掘&#xff0c;就是在交易数据、关系数据或其他信息载体中&#xff0c;查找存在于项目集合或对象集合之间的频繁模式、关联、相关性或因果结构。或者说&#xff0c;关联分析是发现交易数据库中不…

动态网页开发基础【笔记】

一、C/S结构和B/S结构1.C/S&#xff08;Client/Server&#xff09;:客户端服务程序&#xff0c;控制台程序&#xff0c;window应用2.B/S(Browser/Server):浏览器服务程序[java:jsp应用&#xff1b;C#:asp.net],web应用程序区别&#xff1a;C/S:客户端和服务器端都需要开发&…

ASP.NET Core 中文文档 第三章 原理(2)中间件

原文&#xff1a;Middleware作者&#xff1a;Steve Smith and Rick Anderson翻译&#xff1a;刘怡(AlexLEWIS)校对&#xff1a;许登洋(Seay) 章节&#xff1a; 什么是中间件用 IApplicationBuilder 创建中间件管道内置中间件编写中间件扩展资源 查看或下载样例代码 什么是中间件…

关联分析:FP-Growth算法

转载自 关联分析&#xff1a;FP-Growth算法关联分析又称关联挖掘&#xff0c;就是在交易数据、关系数据或其他信息载体中&#xff0c;查找存在于项目集合或对象集合之间的频繁模式、关联、相关性或因果结构。关联分析的一个典型例子是购物篮分析。通过发现顾客放入购物篮中不同…

sql server链接查询

一、连接结果集中有多个表的信息时用连接查询1.内连接:多个表根据公共列连接&#xff0c;符合条件的显示&#xff0c;不符合条件的不显示 2.外连接:多个表根据公共列连接&#xff0c;显示一个表中的所有信息&#xff0c;另个表中中符合条件的信息&#xff0c;不符合条件的用nul…

ASP.NET Core 中文文档 第三章 原理(1)应用程序启动

原文&#xff1a;Application Startup作者&#xff1a;Steve Smith翻译&#xff1a;刘怡(AlexLEWIS)校对&#xff1a;谢炀(kiler398)、许登洋(Seay) ASP.NET Core 为你的应用程序提供了处理每个请求的完整控制。Startup 类是应用程序的入口&#xff08;entry point&#xff09;…

基于内容的推荐(Content-based Recommendations)

转载自 基于内容的推荐&#xff08;Content-based Recommendations&#xff09;Collaborative Filtering Recommendations (协同过滤&#xff0c;简称CF) 是目前最流行的推荐方法&#xff0c;在研究界和工业界得到大量使用。但是&#xff0c;工业界真正使用的系统一般都不会只…

[置顶]动态网页开发基础【笔记】

一、C/S结构和B/S结构1.C/S&#xff08;Client/Server&#xff09;:客户端服务程序&#xff0c;控制台程序&#xff0c;window应用2.B/S(Browser/Server):浏览器服务程序[java:jsp应用&#xff1b;C#:asp.net],web应用程序区别&#xff1a;C/S:客户端和服务器端都需要开发&…

ASP.NET Core 中文文档 第三章 原理(3)静态文件处理

原文&#xff1a;Working with Static Files作者&#xff1a;Rick Anderson翻译&#xff1a;刘怡(AlexLEWIS)校对&#xff1a;谢炀(kiler398)、许登洋(Seay)、孟帅洋(书缘) 静态文件&#xff08;static files&#xff09;&#xff0c;诸如 HTML、CSS、图片和 JavaScript 之类的…

使用IDEA Maven搭建Mybatis环境

本文是使用IDEA Maven搭建Mybatis环境 涉及到的搭配环境 JDK1.8 Maven3.6.3 IDEA2019 MySQL数据库 一、Maven介绍 Maven 是一个项目管理工具&#xff0c;可以对 Java 项目进行构建、依赖管理&#xff0c;是一个自动化构建工具。 自动化构建工具&#xff1a;将原材料&…

常用推荐算法

转载自 常用推荐算法在推荐系统简介中&#xff0c;我们给出了推荐系统的一般框架。很明显&#xff0c;推荐方法是整个推荐系统中最核心、最关键的部分&#xff0c;很大程度上决定了推荐系统性能的优劣。目前&#xff0c;主要的推荐方法包括&#xff1a;基于内容推荐、协同过滤…

不该活着的SqlHelper和DBHelper

前言&#xff1a; 还记得刚学ADO.NET的情景么&#xff1f; 还记得当年是怎么从ADO.NET被忽悠到用SqlHelper的么&#xff1f; 话说从入门到走上工作岗位那些年&#xff0c;我们就一直被纯纯地教导或引导&#xff0c;ADO.NET太原始&#xff0c;得封装成SqlHelper或DBHelper......…

使用IDEA配置Mybatis-Plus框架

使用IDEA配置Mybatis-Plus框架 本文是以使用IDEA配置Mybatis-Plus框架作为简单的讲解。 所涉及到的应用&#xff1a; IDEA2019Mybatis-Plus框架Mysql数据库Maven3.6.3jdk1.8 一、什么是Mybatis-Plus框架&#xff1f; MyBatis-Plus(简称MP)是一个MyBatis的增强工具&#xff…