现在的位置: 首页 > 综合 > 正文

MVC学习笔记五:HTML辅助方法【上】

2017年10月09日 ⁄ 综合 ⁄ 共 8406字 ⁄ 字号 评论关闭

HTML辅助方法

概要

在一些视图中,经常看到类似下面的一些代码:

如:
@Html.TextBox("xxx")
@Html.EditorFor(m=>m.name)
@Html.CheckBox("ccc",new people())
……

这些都是 HtmlHelper类 的扩展方法,该类被称为HTML辅助方法或HTML辅助器,这里先记录下一些常用的HTML辅助器方法,以及如何自定义属于我们自己的扩展方法。



建立默认视图


首先,新建一个MVC3项目,项目名称取为“HtmlSampleApp”,为了方便检查网页里的元素,这里选择空项目。
创建一个控制器"HomeController",为控制器里的Index方法添加一个默认的视图。
默认的视图代码为:
@{
    ViewBag.Title = "这是默认的视图标题";
}

<h2>这是一个默认的原始视图!</h2>

编译运行可以看到:


然后我们右击鼠标查看网页的源码:
<!DOCTYPE html>
<html>
<head>
    <title>这是默认的视图标题</title>
    <link href="/Content/Site.css" rel="stylesheet" type="text/css" />
    <script src="/Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
</head>

<body>
    
<h2>这是一个默认的原始视图!</h2>

</body>
</html>

可以发现, ViewBag.Title为我们生成了网页的title标签值,<h2>标签还是原生的没变。


认识MvcHtmlString

接下来我将视图中的代码改成如下:
@{
    ViewBag.Title = "这是默认的视图标题";
}

<h2>这是一个默认的原始视图!</h2>
@{
    var mvcHtmlString = MvcHtmlString.Create("Hello,World!");
}
<h3>@mvcHtmlString.ToHtmlString()</h3>

运行一下,查看网页源码如下:

<!DOCTYPE html>
<html>
<head>
    <title>这是默认的视图标题</title>
    <link href="/Content/Site.css" rel="stylesheet" type="text/css" />
    <script src="/Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
</head>

<body>
    
<h2>这是一个默认的原始视图!</h2>
<h3>Hello,World!</h3>


</body>
</html>

从定义看到,MvcHtmlString的静态方法Create接受了一个常规字符串string型的参数,处理完成后返回了一个MvcHtmlString类型的实例:

namespace System.Web.Mvc
{
    // 摘要:
    //     Represents an HTML-encoded string that should not be encoded again.
    public sealed class MvcHtmlString : HtmlString
    {
        // 摘要:
        //     Creates an HTML-encoded string using the specified text value.
        //
        // 参数:
        //   value:
        //     The value of the string to create .
        //
        // 返回结果:
        //     An HTML-encoded string.
        public static MvcHtmlString Create(string value);
 
    }
}

而且可以借助父类的ToHtmlString方法将MvcHtmlString转化成用于显示的常规string:

namespace System.Web
{
    // 摘要:
    //     表示不应再次进行编码的 HTML 编码的字符串。
    public class HtmlString : IHtmlString
    {

        // 摘要:
        //     返回 HTML 编码的字符串。
        //
        // 返回结果:
        //     HTML 编码的字符串。
        public string ToHtmlString();

    }
}

接下来我将视图代码中的ToHtmlString方法去掉,即:

@{
    ViewBag.Title = "这是默认的视图标题";
}

<h2>这是一个默认的原始视图!</h2>
@{
    var mvcHtmlString = MvcHtmlString.Create("Hello,World!");
}
<h3>@mvcHtmlString</h3>

生成的源码还是:

<!DOCTYPE html>
<html>
<head>
    <title>这是默认的视图标题</title>
    <link href="/Content/Site.css" rel="stylesheet" type="text/css" />
    <script src="/Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
</head>

<body>
    
<h2>这是一个默认的原始视图!</h2>
<h3>Hello,World!</h3>




</body>
</html>
接下来对Create参数赋予另一种格式的字符串,如下:
@{
    ViewBag.Title = "这是默认的视图标题";
}

<h2>这是一个默认的原始视图!</h2>
@{
    var mvcHtmlString = MvcHtmlString.Create("Hello,World!");
}
<h3>@mvcHtmlString</h3>

@{
    var mvcHtmlStringTextBox = MvcHtmlString.Create("<input type=\"text\" name=\"text1\" value=\"Hello World!\" />");
}
@mvcHtmlStringTextBox.ToHtmlString()
@mvcHtmlStringTextBox

返回的网页:

源码是:
<!DOCTYPE html>
<html>
<head>
    <title>这是默认的视图标题</title>
    <link href="/Content/Site.css" rel="stylesheet" type="text/css" />
    <script src="/Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
</head>

<body>
    
<h2>这是一个默认的原始视图!</h2>
<h3>Hello,World!</h3>

&lt;input type=&quot;text&quot; name=&quot;text1&quot; value=&quot;Hello World!&quot; /&gt;
<br />
<input type="text" name="text1" value="Hello World!" />


</body>
</html>

说明MvcHtmlString实例的ToHtmlString方法是将字符串显示出来,而如果网页中直接返回MvcHtmlString,那么如果遇到控件标签则会被解释成html控件。


那如果我故意将控件标签或属性写错会发生什么现象么,这里试一下,我将input写成inpuat,name写成nae:
@{
    ViewBag.Title = "这是默认的视图标题";
}

<h2>这是一个默认的原始视图!</h2>
@{
    var mvcHtmlString = MvcHtmlString.Create("Hello,World!");
}
<h3>@mvcHtmlString</h3>

@{
    var mvcHtmlStringTextBox = MvcHtmlString.Create("<inpuat type=\"text2\" nae=\"text1\" value=\"Hello World!\" />");
}
@mvcHtmlStringTextBox.ToHtmlString()
<br />
@mvcHtmlStringTextBox

运行:


可以看到textbox控件并没有出现在网页,查看一下源码:
<!DOCTYPE html>
<html>
<head>
    <title>这是默认的视图标题</title>
    <link href="/Content/Site.css" rel="stylesheet" type="text/css" />
    <script src="/Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
</head>

<body>
    
<h2>这是一个默认的原始视图!</h2>
<h3>Hello,World!</h3>

&lt;inpuat type=&quot;text2&quot; nae=&quot;text1&quot; value=&quot;Hello World!&quot; /&gt;
<br />
<inpuat type="text2" nae="text1" value="Hello World!" />


</body>
</html>

可以看到,如果输错标签,那么网页上就不会出现对应的控件。应该是浏览器解析不了吧,什么都不会显示出来。

接下来我将标签改正确,type属性改成任意值:
@{
    ViewBag.Title = "这是默认的视图标题";
}

<h2>这是一个默认的原始视图!</h2>
@{
    var mvcHtmlString = MvcHtmlString.Create("Hello,World!");
}
<h3>@mvcHtmlString</h3>

@{
    var mvcHtmlStringTextBox = MvcHtmlString.Create("<input type=\"12345abc\" nae=\"text1\" value=\"Hello World!\" />");
}
@mvcHtmlStringTextBox.ToHtmlString()
<br />
@mvcHtmlStringTextBox

结果居然是:


可见浏览器解析时将不确定的type类型直接默认成text。

实际上,也可以通过MvcHtmlString的构造函数来创建MvcHtmlString,如:
@{
    ViewBag.Title = "这是默认的视图标题";
}
<h2>这是一个默认的原始视图!</h2>

@{
    var mvcHtmlStringInstance=new  MvcHtmlString("<input type=\"text\" name=\"text2\" value=\"Merry Christmas!\" />");
}
@mvcHtmlStringInstance

对应的源码:

<!DOCTYPE html>
<html>
<head>
    <title>这是默认的视图标题</title>
    <link href="/Content/Site.css" rel="stylesheet" type="text/css" />
    <script src="/Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
</head>

<body>
    <h2>这是一个默认的原始视图!</h2>

<input type="text" name="text2" value="Merry Christmas!" />


</body>
</html>

也可以将MvcHtmlString保存在集合中,利用特殊形式显示出来(这里使用遍历),如

@{
    ViewBag.Title = "MvcHtmlString";
}
<h2>这是一个MvcHtmlString使用示例!</h2>

@{
    var mvcHtmlStringList = new List<MvcHtmlString>()
    {
        new MvcHtmlString("<input type=\"text\" name=\"text1\" value=\"Merry Christmas!\" /> <br />"),
        new MvcHtmlString("<input type=\"text\" name=\"text2\" value=\"Merry Christmas!\" /><br />"),
        new MvcHtmlString("<input type=\"text\" name=\"text3\" value=\"Merry Christmas!\" /><br />"),
        new MvcHtmlString("<input type=\"text\" name=\"text4\" value=\"Merry Christmas!\" /><br />")        
    };
}
@foreach (var item in mvcHtmlStringList)
{
    @item
}

显示:


源码:
<!DOCTYPE html>
<html>
<head>
    <title>MvcHtmlString</title>
    <link href="/Content/Site.css" rel="stylesheet" type="text/css" />
    <script src="/Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
</head>

<body>
    <h2>这是一个MvcHtmlString使用示例!</h2>

<input type="text" name="text1" value="Merry Christmas!" /> <br /><input type="text" name="text2" value="Merry Christmas!" /><br /><input type="text" name="text3" value="Merry Christmas!" /><br /><input type="text" name="text4" value="Merry Christmas!" /><br />

</body>
</html>

认识TagBuilder

这个类用于创建HTML元素,就是类似上面的:

<input type=\"text\" name=\"text1\" value=\"Merry Christmas!\" /> <br />

上面是手工敲的HTML元素,使用TagBuilder只不过是用另一种形式进行HTML元素的编写。
如:

@{
    ViewBag.Title = "TagBuilder";
}
<h2>这是一个TagBuilder使用示例!</h2>

@{
    var tagbulider = new TagBuilder("input");
    tagbulider.Attributes.Add("type", "text");
    tagbulider.Attributes.Add("name", "text1");
    tagbulider.Attributes.Add("value", "Hello,world~");
    tagbulider.GenerateId("id1");
    var mvchtmlString = MvcHtmlString.Create(tagbulider.ToString(TagRenderMode.SelfClosing));
}
@mvchtmlString

生成的网页元素是:

<!DOCTYPE html>
<html>
<head>
    <title>TagBuilder</title>
    <link href="/Content/Site.css" rel="stylesheet" type="text/css" />
    <script src="/Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
</head>

<body>
    <h2>这是一个TagBuilder使用示例!</h2>

<input id="id1" name="text1" type="text" value="Hello,world~" />

</body>
</html>

以上是简单的TagBuilder示例,有关它的详细说明见这里

扩展HtmlHelper类

下面记录一下如何扩展HtmlHelper类,首先在项目下新建一个文件夹“MyManagers”,在文件夹里新建一个类“MyExternMethods.cs”

将类代码修改为:
        public static MvcHtmlString MyInput(this HtmlHelper htmlhelper, string name)
        {
            TagBuilder tag = new TagBuilder("input");
            tag.Attributes.Add("type", "text");
            tag.Attributes.Add("name", name);
            tag.Attributes.Add("value", "Hello,world~");
            tag.GenerateId("id1");
            return MvcHtmlString.Create(tag.ToString(TagRenderMode.SelfClosing));
        }

然后,在Index视图文件文件中将代码修改为:

@using HtmlSampleApp.MyManagers;

@{
    ViewBag.Title = "HtmlHelper扩展方法示例";
}

<h2>这是一个HtmlHelper扩展方法示例!</h2>
@{
    @Html.MyInput("myname");
}

编译运行,可以看到网页源码为:

<!DOCTYPE html>
<html>
<head>
    <title>HtmlHelper扩展方法示例</title>
    <link href="/Content/Site.css" rel="stylesheet" type="text/css" />
    <script src="/Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
</head>

<body>
    

<h2>这是一个HtmlHelper扩展方法示例!</h2>
<input id="id1" name="myname" type="text" value="Hello,world~" />
</body>
</html>

然后再新建另一个扩展方法,支持lambda表达式:

        public static MvcHtmlString AnotherInput<TModel, TResult>(this  HtmlHelper<TModel> htmlhelper, Expression<Func<TModel, TResult>> expression)
        {
            var property = expression.Body as MemberExpression;

            TagBuilder tag = new TagBuilder("input");
            tag.Attributes.Add("type", "text");
            tag.Attributes.Add("name", property.ToString());
            tag.Attributes.Add("value", "Merry Christmas~");
            tag.GenerateId("id1");
            return MvcHtmlString.Create(tag.ToString(TagRenderMode.SelfClosing));
        }
修改视图代码:
@using HtmlSampleApp.MyManagers;
@model HtmlSampleApp.Models.Sheep
@{
    ViewBag.Title = "Index";
}

<h2>Index</h2>

@{
    @Html.AnotherInput(m => m.name);
}

编译运行,查看源码:

<!DOCTYPE html>
<html>
<head>
    <title>Index</title>
    <link href="/Content/Site.css" rel="stylesheet" type="text/css" />
    <script src="/Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
</head>

<body>
    
<h2>Index</h2>

<input id="id1" name="m.name" type="text" value="Merry Christmas~" />
</body>
</html>

看到,name的属性值就是lambda表达式的参数表达式(而不是表达式的值)。如果需要表达式的值,估计要使用反射,这里我还不清楚如何用。


待续……


抱歉!评论已关闭.