简体   繁体   English

如果在页面底部呈现捆绑脚本,如何使用动态JQuery脚本定义部分视图?

[英]How can I define partial views with dynamic JQuery scripts if bundled scripts are rendered at the bottom of the page?

I have a web application using MVC4 and Razor views that utilize a lot of JQuery and other plugin scripts. 我有一个使用MVC4和Razor视图的Web应用程序,它们使用了大量的JQuery和其他插件脚本。

For speeding up the rendering of views, I believe that in general, it is good practice to render the scripts at the bottom of the body, so the layout (much consolidated) looks like the following: 为了加快视图的渲染速度,我相信一般来说,最好将脚本渲染到正文的底部,因此布局(大大合并)如下所示:

<body>
    @RenderBody()

    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/other")

    @RenderSection( "Scripts", false )
</body>

The Scripts section allows particular views to add additional JQuery functions, and they are guaranteed to be rendered after the JQuery library. Scripts部分允许特定视图添加其他JQuery函数,并且保证它们在JQuery库之后呈现。 So far, so good. 到现在为止还挺好。

Now consider the following snippet in a view, which renders a partial for each item in a collection: 现在考虑视图中的以下片段,该片段为集合中的每个项目呈现部分:

@foreach (var item in Model.Items)
{
    Html.RenderPartial("_MyPartial", item);
}

This partial (_MyPartial) needs to render JQuery for controls based on collection item details such as the following snippet: 这个部分(_MyPartial)需要根据集合项详细信息(如下面的代码段)为控件呈现JQuery:

$(function () {
    $("#@(Model.Id)").click(function () {
        // do something when control on partial with id Model.Id is clicked
        alert("I've been clicked!");
    });
});

The partial view JQuery functions do not get executed, because the JQuery library is not loaded prior to the _MyPartial scripts for each collection item. 部分视图JQuery函数不会被执行,因为在每个集合项的_MyPartial脚本之前没有加载JQuery库。 Running in chrome debugger shows $ not defined , which confirms this. 在chrome调试器中运行显示$ not defined ,这证实了这一点。

I could do something real ugly, such as replicating each foreach statement in the scripts section for all views that call the partial and then have the parent view generate the scripts. 我可以做一些非常丑陋的事情,例如在脚本部分复制每个foreach语句,用于调用partial的所有视图,然后让父视图生成脚本。 But, this in effect kills the re-usability of the partial view. 但是,这实际上会破坏局部视图的可重用性。

Is there a way to get Razor partial view scripts to render late (such as in parent scripts section), or a different approach to this issue? 有没有办法让Razor部分视图脚本延迟渲染(例如在父脚本部分中),或者是针对此问题的不同方法?

Unfortunately sections are not supported in partial views. 不幸的是,部分视图中不支持部分。 One possibility is to write custom helpers as I illustrated in this post: https://stackoverflow.com/a/9663249/29407 一种可能性是编写自定义帮助程序,如本文所述: https//stackoverflow.com/a/9663249/29407

This would allow you to have a placeholder helper invoked at the end of the document which will render all scripts that have been registered in partials. 这将允许您在文档末尾调用占位符助手,该助手将呈现已在partials中注册的所有脚本。

This being said, it is usually a better idea to expose the client side functionality that your partial needs as a jQuery plugin. 这就是说,通常更好的方法是将您部分需要的客户端功能公开为jQuery插件。 Then it is trivially easy to invoke this plugin on some DOM elements: 然后在一些DOM元素上调用此插件非常容易:

$('.someElement').somePlugin();

This way you no longer need to be doing any $("#@(Model.Id)") in your partials. 这样你就不再需要在你的部分中做任何$("#@(Model.Id)") The partials shouldn't have any scripts in them normally. 部分通常不应包含任何脚本。

For reference, I used Darin's solution, and also extended it for cases in which I needed to register raw script that isn't located in a file. 作为参考,我使用了Darin的解决方案,并且还针对我需要注册不在文件中的原始脚本的情况进行了扩展。 The additional methods are: 其他方法是:

public static class HtmlExtensions
{
    public static IHtmlString RegisteredRawScripts(this HtmlHelper htmlHelper)
    {
        var ctx = htmlHelper.ViewContext.HttpContext;
        var registeredScripts = ctx.Items["_rawscripts_"] as Stack<string>;
        if (registeredScripts == null || registeredScripts.Count < 1)
        {
            return null;
        }
        var sb = new StringBuilder();
        foreach (var script in registeredScripts)
        {
            sb.AppendLine("\r\n" + script);
        }
        return new HtmlString(sb.ToString());
    }

    public static void RegisterRawScript(this HtmlHelper htmlHelper, string script)
    {
        var ctx = htmlHelper.ViewContext.HttpContext;
        var registeredScripts = ctx.Items["_rawscripts_"] as Stack<string>;
        if (registeredScripts == null)
        {
            registeredScripts = new Stack<string>();
            ctx.Items["_rawscripts_"] = registeredScripts;
        }
        if (!registeredScripts.Contains(script))
        {
            registeredScripts.Push(script);
        }
    }
}

In your partial, you do something like: 在你的部分,你做的事情如下:

@Html.RegisterRawScript(script);  // where script is your raw script as a string

And in your layout, you register your raw scripts: 在您的布局中,您注册了原始脚本:

@Html.RegisteredRawScripts()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM