在部分视图中包含页面底部的JavaScript

Did*_*xis 10 .net javascript c# asp.net-mvc asp.net-mvc-3

假设我在局部视图中有一个javascript幻灯片放映...

_Slideshow.cshtml:

@{
    ViewBag.Title = "Slide Show";
}
<div id="slides">
</div>
<script src="js/slides.min.jquery.js"></script>
<script type="text/javascript">
$(function(){
    $('#slides').slides({
        // slide show configuration...
    });
});
</script>
Run Code Online (Sandbox Code Playgroud)

但我想成为一名优秀的小型Web开发人员,并确保我的所有脚本都位于页面底部.所以我会让我的*_Layout.cshtml*页面看起来像这样:

_Layout.cshtml:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>@ViewBag.Title</title>
    <link href="@Url.Content("~/css/global.css")" rel="stylesheet" type="text/css" />
</head>
<body>
    <div id="wrapper">
    @RenderBody
    </div>
    <!-- Being a good little web developer, I include my scripts at the BOTTOM, yay!
    -->
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js" type="text/javascript"></script>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

但是UH OH!我现在该怎么做,因为我的幻灯片脚本最终超出了我的jQuery包含范围?!如果我想在每个页面上播放幻灯片,这不会是什么大不了的事,但我只希望幻灯片放映部分视图在某个页面上呈现,并且......我希望我的脚本在底部!该怎么办?

Bec*_*uzz 10

您可以在布局页面中为脚本定义一个部分,如下所示:

<body>
    <div id="wrapper">
    @RenderBody
    </div>
    <!-- Being a good little web developer, I include my scripts at the BOTTOM, yay!
    -->
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js" type="text/javascript"></script>
    @RenderSection("myScripts")
</body>
Run Code Online (Sandbox Code Playgroud)

然后在您的页面上定义该部分的内容:

@{
    ViewBag.Title = "Slide Show";
}
<div id="slides">
</div>
@section myScripts { //put your scripts here
    <script src="js/slides.min.jquery.js"></script>
    <script type="text/javascript">
    $(function(){
        $('#slides').slides({
            // slide show configuration...
        });
    });
    </script>
}
Run Code Online (Sandbox Code Playgroud)

然后,当页面呈现时,它将获取您的部分中的所有内容并将其添加到应该放置在布局页面上的位置(在本例中,在底部).

  • 注意:这在部分视图中添加"部分"不起作用(因为只是平面不起作用!)相反,我不得不将"部分"添加到视图本身,但也工作得很好! (4认同)

Kyl*_*Mit 6

注意:已接受的解决方案不适 用于问题要求的部分视图

问题

在正常流程中,您可以使用声明从 ActionResult 的父视图内部定义特定部分的内容。当该视图最终插入其 LayoutPage 时,它​​可以调用将这些内容放置在页面内的任何位置,从而允许您定义一些内联 JavaScript,这些 JavaScript 可以在它依赖的任何核心库之后在页面底部呈现和解析像这样:@section SectionName {}RenderSection

布局 > 全视图

当您希望能够在部分视图中重用完整页面视图时,就会出现问题。也许您还想将视图重新用作另一个页面内部的小部件或对话框。在这种情况下,完整的局部视图会在您调用父视图的任何地方@Html.EditorFor@Html.Partial在父视图内部完整呈现,如下所示:

布局 > 父视图 > 局部视图

根据MSDN Docs on Layouts with Razor Syntax

  • 视图中定义的部分仅在其直接布局页面中可用。
  • 部分不能从局部、视图组件或视图系统的其他部分引用。
  • 内容页面中的正文和所有部分都必须由布局页面呈现

在这种情况下,将定义到页面底部的局部视图中的脚本变得棘手。根据文档,您只能RenderSection从布局视图调用,而不@section能从局部视图内部定义内容,因此所有内容都集中在同一区域,您的脚本将从 HTML 的中间呈现、解析和运行页面,而不是底部,在它可能依赖的任何库之后。

解决方案

要全面讨论将部分视图从部分视图注入页面的多种方法,我将从 StackOverflow 上的以下两个问题开始:

其中不同的解决方案在对嵌套、排序、多脚本支持、不同的内容类型、调用语法和可重用性的支持方面有所不同。但是无论你如何分割,几乎任何解决方案都必须完成两个基本任务:

  1. 从任何页面、部分视图或模板中逐步将脚本对象构建到您的请求上,可能会利用某种 HtmlHelper 扩展来实现可重用性。
  2. 将该脚本对象呈现到您的布局页面上。由于布局页面实际上是最后呈现的,这只是将我们一直在构建的对象发射到母版页上。

这里有一个简单的实现达林季米特洛夫

添加帮助程序扩展方法,这将允许您将任意脚本对象构建到ViewContent.HttpContext.Items集合中,然后稍后获取和呈现它们。

实用工具.cs

public static class HtmlExtensions
{
    public static MvcHtmlString Script(this HtmlHelper htmlHelper, Func<object, HelperResult> template)
    {
        htmlHelper.ViewContext.HttpContext.Items["_script_" + Guid.NewGuid()] = template;
        return MvcHtmlString.Empty;
    }

    public static IHtmlString RenderScripts(this HtmlHelper htmlHelper)
    {
        foreach (object key in htmlHelper.ViewContext.HttpContext.Items.Keys)
        {
            if (key.ToString().StartsWith("_script_"))
            {
                var template = htmlHelper.ViewContext.HttpContext.Items[key] as Func<object, HelperResult>;
                if (template != null)
                {
                    htmlHelper.ViewContext.Writer.Write(template(null));
                }
            }
        }
        return MvcHtmlString.Empty;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以在你的应用程序中像这样使用

像这样在局部视图中构建这个脚本对象,如下所示:

@Html.Script(
    @<script>
         $(function() {
             $("#@Html.IdFor(model => model.FirstName)").change(function() {
                 alert("New value is '" + this.value + "'");
             });
         })
     </script>
)
Run Code Online (Sandbox Code Playgroud)

然后像这样在你的LayoutPage 中的任何地方渲染它们:

@Scripts.Render("~/bundles/jquery")
@RenderSection("scripts", required: false)
@Html.RenderScripts()
Run Code Online (Sandbox Code Playgroud)