我们力求页面层代码简洁并具有较好的可读性,在ASP.NET MVC的平台上,我们以新的起点来实现这一目标.MvcContrib.FluentHtml和Spark ViewEngine给我们做出了榜样.本文将以MvcContrib.FluentHtml为例探究它的实现机制:Fluent Interface.
10余年的彭山网站建设经验,针对设计、前端、开发、售后、文案、推广等六对一服务,响应快,48小时及时工作处理。成都全网营销推广的优势是能够根据用户设备显示端的尺寸不同,自动调整彭山建站的显示方式,使网站能够适用不同显示终端,在浏览器中调整网站的宽度,无论在任何一种浏览器上浏览网站,都能展现优雅布局与设计,从而大程度地提升浏览体验。创新互联从事“彭山网站设计”,“彭山网站推广”以来,每个客户项目都认真落实执行。
在MvcContrib.FluentHtml的应用中,我们随处可以见到下面的代码:
- < %= this.TextBox(x => x.Person.Name).Title("Enter the person's name").Label("Name:") %>
- ……
- < %= this.Select(x => x.Person.Gender).Options(Model.Genders).Size(5).Label("Gender:")
- .Title("Select the person's gender") %>
浏览器中生成的代码为:
- < LABEL id=Person_Name_Label for=Person_Name>Name:< /LABEL>
- < INPUT id=Person_Name title="Enter the person's name" value=Jeremy maxLength=50 name=Person.Name>
- .
- < SELECT id=Person_Gender title="Select the person's gender" size=5 name=Person.Gender>< OPTION selected value=M>Male< /OPTION>< OPTION value=F>Female< /OPTION>< /SELECT>
上面对动态生成TextBox和Select的代码很有意思,我们使用普通的方式在页面上生成同样的客户端代码,CS代码大致是这样的:
- Label label = new Label();
- label.Text = "Name";
- TextBox textbox= new TextBox();
- textbox.ToolTip ="Enter the person's name";
- textbox.ID = "No.10001";
- textbox.ID = "Person.Name";
而FluentHtml创建页面元素的方式让我们很容易联想到StringBuilder的使用:
- StringBuilder stringbuilder = new StringBuilder();
- stringbuilder.Append("Hello").Append(" ").Append("World!");
Fulent Interface 这种实现编程方式就是"Fluent Interface",这并不是什么新概念,2005年Eric Evans 和Martin Fowler就为这种实现方式命名.源文档
我们分解上面的话:
它是面向对象API的一种实现方式,目的是增加代码的可读性.。既然我们最熟悉的是StringBuilder,我们就从这个线索追下去:打开Reflector,很容易找到StringBuilder的Append方法:
- public StringBuilder Append(string value)
- {
- if (value != null)
- {
- string stringValue = this.m_StringValue;
- IntPtr currentThread = Thread.InternalGetCurrentThread();
- if (this.m_currentThread != currentThread)
- {
- stringstringValue = string.GetStringForStringBuilder(stringValue, stringValue.Capacity);
- }
- int length = stringValue.Length;
- int requiredLength = length + value.Length;
- if (this.NeedsAllocation(stringValue, requiredLength))
- {
- string newString = this.GetNewString(stringValue, requiredLength);
- newString.AppendInPlace(value, length);
- this.ReplaceString(currentThread, newString);
- }
- else
- {
- stringValue.AppendInPlace(value, length);
- this.ReplaceString(currentThread, stringValue);
- }
- }
- return this;
- }
阅读这段有两个特别要注意的点:1.方法的返回值是StringBuilder类型 2.***一句:return this;为了深刻理解,我们写一个简单的StringBuilder:
- public interface IContentBuilder
- {
- void WriteContent();
- IContentBuilder Append(string partialContent);
- }
- public class TestContentBuilder : IContentBuilder
- {
- string temp;
- #region IContentBuilder Members
- void IContentBuilder.WriteContent()
- {
- Console.Write(temp);
- }
- IContentBuilder IContentBuilder.Append(string partialContent)
- {
- temp += partialContent;
- return this;
- }
- #endregion
- }
- … …
- //调用代码
- IContentBuilder t = new TestContentBuilder();
- t.Append("test").Append("Hello").WriteContent();
跑一下代码,和StringBuilder效果是一样的.从上面的应用也可以看出:Fluent Interface经常用来完成对象的构造和属性赋值.
言归正传:FluentHTML了解了Fluent Interface,我们来看一下MVCContrib.FluentHTML的实现,这里以TextBox为例进行考察,首先看一下它的继承关系:
- public class TextBox : TextInput
- public abstract class TextInput : Input, ISupportsMaxLength where T : TextInput
- public abstract class Input : FormElement where T : Input, Ielement
泛型是一种高层次的算法抽象,我们就通过Input 一窥端倪:
- public abstract class Input : FormElement where T : Input, IElement
- {
- protected object elementValue;
- protected Input(string type, string name) : base(HtmlTag.Input, name)
- {
- builder.MergeAttribute(HtmlAttribute.Type, type, true);
- }
- protected Input(string type, string name, MemberExpression forMember, IEnumerable behaviors)
- : base(HtmlTag.Input, name, forMember, behaviors)
- {
- builder.MergeAttribute(HtmlAttribute.Type, type, true);
- }
- ///
- /// Set the 'value' attribute.
- ///
- /// The value for the attribute.
- public virtual T Value(object value)
- {
- elementValue = value;
- return (T)this;
- }
- ///
- /// Set the 'size' attribute.
- ///
- /// The value for the attribute.
- public virtual T Size(int value)
- {
- Attr(HtmlAttribute.Size, value);
- return (T)this;
- }
- protected override void PreRender()
- {
- Attr(HtmlAttribute.Value, elementValue);
- base.PreRender();
- }
- }
- 以Size方法为例,可以看出这是一种典型的Fluent Interface实现:
- public virtual T Size(int value)
- {
- Attr(HtmlAttribute.Size, value);
- return (T)this;
- }
分析到这里,上面的语句中还有一点比较奇怪,就是Lambda表达式的部分:
- this.TextBox(x => x.Person.Name).Title("Enter the person's name").Label("Name:")
TextBox的实现代码里面我们没有看到对Lambda表达式的支持.那是在什么地方完成的呢?通过跟进,我们来到了ViewDataContainerExtensions,它是IViewDataCon
- namespace MvcContrib.FluentHtml
- {
- ///
- /// Extensions to IViewDataContainer
- ///
- public static class ViewDataContainerExtensions
- {
- ///
- /// Generate an HTML input element of type 'text' and set its value from ViewData based on the name provided.
- ///
- /// The view.
- /// Value of the 'name' attribute of the element.Also used to derive the 'id' attribute.
- public static TextBox TextBox(this IViewDataContainer view, string name)
- {
- return new TextBox(name).Value(view.ViewData.Eval(name));
- }
- … …
tainer 的Extension Method:
看一下return new TextBox(name).Value(view.ViewData.Eval(name));所以这里就成了TextBox定义方法链的***步.
FluentHtml与连续接口总结
为了能够在View中能够简洁清晰的构造HTML元素,Asp.net MVC中通过htmlHelper.InputHelper来实现页面元素的构造. 页面层所使用的<%= Html.TextBox("username") %>,HTML也是htmlHelper的Extension Method.相比较起来,htmlHelper提供了基础的页面控件定义和构造,而FluentHTML表现的更为灵活.除了FluentHTML,著名的Spark View Engine也有类似的实现,大家可以关注一下.
【编辑推荐】
本文题目:浅谈ASP.NETMVC中的FluentHtml与连续接口
分享网址:http://www.gawzjz.com/qtweb/news43/205843.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联