1

我想创建需要包含 Javascript/CSS 文件才能正常运行的部分视图。同一个局部视图可以在一个页面中多次包含,因此如果我将 Javascript/CSS 文件嵌入到局部视图 HTML 内容中,这些文件将被嵌入 N 次。我希望这些文件只嵌入一次。

此外,此类局部视图正在使用该Html.Action方法呈现,以便利用输出缓存,因此 Action 方法不会一直执行。

我的想法是使用一些管理此类嵌入的控制器在部分视图中注册 javascript/css 文件,然后将它们输出到页面的脚本部分,在结束</body>标记之前的底部,但由于操作将被缓存,例如代码不保证执行,但可以从缓存中加载。

对于这种情况的最佳实践有什么建议吗?

4

1 回答 1

2

您可以定义 2 个自定义助手:

public static class HtmlExtensions
{
    public static IHtmlString RenderRegisteredScripts(this HtmlHelper htmlHelper)
    {
        var ctx = htmlHelper.ViewContext.HttpContext;
        var registeredScripts = ctx.Items["_scripts_"] as Stack<string>;
        if (registeredScripts == null || registeredScripts.Count < 1)
        {
            return null;
        }
        var sb = new StringBuilder();
        foreach (var script in registeredScripts)
        {
            var scriptBuilder = new TagBuilder("script");
            scriptBuilder.Attributes["type"] = "text/javascript";
            scriptBuilder.Attributes["src"] = script;
            sb.AppendLine(scriptBuilder.ToString(TagRenderMode.Normal));
        }
        return new HtmlString(sb.ToString());
    }

    public static void RegisterScript(this HtmlHelper htmlHelper, string script)
    {
        var ctx = htmlHelper.ViewContext.HttpContext;
        var urlHelper = new UrlHelper(htmlHelper.ViewContext.RequestContext);
        var registeredScripts = ctx.Items["_scripts_"] as Stack<string>;
        if (registeredScripts == null)
        {
            registeredScripts = new Stack<string>();
            ctx.Items["_scripts_"] = registeredScripts;
        }
        var src = urlHelper.Content(script);
        if (!registeredScripts.Contains(src))
        {
            registeredScripts.Push(src);
        }
    }
}

然后有一个_Layout.cshtml你在最后调用RenderRegisteredScripts助手的地方:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>@ViewBag.Title</title>
    <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
</head>
<body>
    @RenderBody()
    <script src="@Url.Content("~/Scripts/jquery-1.7.1.min.js")" type="text/javascript"></script>
    @RenderSection("Scripts", required: false)
    @Html.RenderRegisteredScripts()
</body>
</html>

现在您可以拥有一个视图,它可以根据需要多次渲染部分部分:

@for (int i = 0; i < 10; i++)
{
    @Html.Partial("_Foo")    
}

@Html.Action("Bar")

并在此部分 ( _Foo.cshtml) 中使用RegisterScript帮助程序为此部分注册依赖脚本:

@{Html.RegisterScript("~/scripts/foo.js");}

现在,当您查看生成的 HTML 标记时,该脚本仅包含一次:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
    <link href="/Content/Site.css" rel="stylesheet" type="text/css" />
</head>
<body>
    <script src="/Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
    <script src="/scripts/foo.js" type="text/javascript"></script>
</body>
</html>
于 2013-02-04T13:19:34.800 回答