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

Jos*_*ard 33 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>
}
Run Code Online (Sandbox Code Playgroud)

我想知道,是否有可能重新使用这个助手来填充.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>
}
Run Code Online (Sandbox Code Playgroud)

虽然使用.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>
}
Run Code Online (Sandbox Code Playgroud)

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

您可以使用此处所示@section语法执行非常类似的操作

在此输入图像描述

这似乎是能够做到的事情真的很有用的东西,奇怪的是在组件级别上没有简单的方法可以做到这一点.

小智 39

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

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>
}
Run Code Online (Sandbox Code Playgroud)

用法:

@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>
)
Run Code Online (Sandbox Code Playgroud)

您的函数也可以接受参数,例如这里.

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>"
            );
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

@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>
}
Run Code Online (Sandbox Code Playgroud)

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