使用ASP.NET MVC中的Razor创建可重用的HTML视图组件

时间:2014-05-07 12:57:40

标签: asp.net asp.net-mvc razor

我有一个Razor辅助函数,可以创建一个可重复使用的HTML面板,可以让我一遍又一遍地编写相同的HTML。

@helper DefaultPanel(string panelTitle) {
    <div class="panel">
        <div class="panel-logo"><img src="/logo.png"></div>
            <div class=panel-inner">
                <p class="panel-title">@panelTitle</p>
                <div class="panel-content">
                    /* Can I pass content to be rendered in here here? */
                </div>
            </div>
        </div>
    </div>
}

我想知道,是否有可能重新使用此帮助程序为.panel-content填充更多HTML以允许进一步的灵活性和代码重用 - 类似如下所示:

@LayoutHelpers.DefaultPanel("Welcome back") {
    <div class="panel-content-inner">
        <p>Welcome back, please select from the following options</p>
        <a href="#">Profile</a>
        <a href="#">My Defails</a>
    </div>
}

虽然使用.NET MVC我注意到Html.BeginForm()@using声明中的Html.BeginForm语句中包装代码时做了类似的事情,如下所示:

@using (Html.BeginForm("Index", "Login", FormMethod.Post))
{
    <div>This content gets rendered within the <form></form> markup.</div>
}

但这可以使用@helper方法完成吗?如果没有,是否可以创建HtmlHelper扩展程序来执行与Html.BeginForm()方法相似的操作?

您可以使用@section

中的{{1}}语法执行非常类似的操作

enter image description here

这似乎是能够做到的事情非常有用的事情,并且奇怪的是,在组件级别上没有简单的方法。

2 个答案:

答案 0 :(得分:38)

有两种方法可以实现所需的功能。

<强> 1。 @helper

创建@helper,它接受你需要的任何参数以及一个函数(单个对象参数,返回对象):

@helper DefaultPanel(string panelTitle, Func<object, object> content)
{
    <div class="panel">
        <div class="panel-logo">
                <img src="/logo.png" />
            </div>
            <div class="panel-inner">
                <p class="panel-title">@panelTitle</p>
                <div class="panel-content">
                    @content(null)
                </div>
            </div>
    </div>
}

用法:

@DefaultPanel("title",
@<div class="panel-content-inner">
    <p>Welcome back, please select from the following options</p>
    <a href="#">Profile</a>
    <a href="#">My Defails</a>
</div>
)

您的功能也可以接受参数,例如here

<强> 2。 HtmlHelper扩展方法

在项目的任何位置添加以下代码:

namespace System.Web.Mvc
{
    public static class HtmlHelperExtensions
    {
        public static HtmlDefaultPanel DefaultPanel(this HtmlHelper html, string title)
        {
            html.ViewContext.Writer.Write(
            "<div class=\"panel\">" +
            "<div class=\"panel-inner\">" +
            "<p class=\"panel-title\">" + title + "</p>" +
            "<div class=\"panel-content\">"
            );

            return new HtmlDefaultPanel(html.ViewContext);
        }
    }

    public class HtmlDefaultPanel : IDisposable
    {
        private readonly ViewContext _viewContext;
        public HtmlDefaultPanel(ViewContext viewContext)
        {
            _viewContext = viewContext;
        }
        public void Dispose()
        {
            _viewContext.Writer.Write(
            "</div>" +
            "</div>" +
            "</div>"
            );
        }
    }
}

用法:

@using (Html.DefaultPanel("title2"))
{
    <div class="panel-content-inner">
        <p>Welcome back, please select from the following options</p>
        <a href="#">Profile</a>
        <a href="#">My Defails</a>
    </div>
}

扩展方法直接写入上下文。诀窍是返回一个一次性对象,Dispose方法将在using块结束时执行。

答案 1 :(得分:1)

我不知道@helper方法是否可以执行此操作,但HtmlHelper扩展当然可以。您已经提到了可能是最知名的Html.BeginForm()示例 - 所有这一切都返回一个实现IDisposable的对象,这意味着当调用Dispose()方法时它只是调用免费的Html.EndForm()方法来添加适当的结束标记。

为HTML代码执行类似的操作非常简单。您可以在http://aspnetwebstack.codeplex.com/查看ASP.NET MVC HtmlHelpers的源代码 - BeginForm()代码可以是viewed here