Include JavaScript file in partial views

后端 未结 9 1473
别跟我提以往
别跟我提以往 2020-12-02 06:13

I am wondering what the best practice is for including javascript files inside partial views. Once rendered this will end up as a js include tag in the middle of my page\'s

相关标签:
9条回答
  • 2020-12-02 06:28

    My preference will be to create a plugin.master page that inherits from your main Site.master. The idea is that you stuff these plugins into plugin.master and make the 8 or so pages that will use this partial view to inherit from plugin.master.

    0 讨论(0)
  • 2020-12-02 06:33

    This seems like a similar (although not entirely) question. Is it bad practice to return partial views that contain javascript?

    0 讨论(0)
  • 2020-12-02 06:36

    hejdig.

    Playing around with Aspnetmvc3 I decided, for now, to just include my javascript file in the partial

    <script src="@Url.Content("~/Scripts/User/List.js")" type="text/javascript"></script>

    This js file is then specific for my /user/List.schtml file.

    /OF

    0 讨论(0)
  • 2020-12-02 06:38

    The reason you would put a script at the bottom of the page is to ensure the dom has been loaded before attempting any manipulation. This can also be achieved in something like the $(document).ready(callback); jQuery method.

    I share the view of not putting embedded JavaScript in the html. Instead I use an Html helper to create an empty div to use as a server instruction. The helper sig is Html.ServerData(String name, Object data);

    I use this ServerData method for instructions from the server to the client. The div tag keeps it clean and the "data-" attribute is valid html5.

    For the loadScript instruction I may do something like this in my ascx or aspx:

    <%= Html.ServerData("loadScript", new { url: "pathTo.js" }) %>
    

    Or add another helper to do this which looks a little cleaner:

    <%= Html.LoadScript("~/path/to.js") %>

    The html output would be:

    <div name="loadScript" data-server="encoded json string">

    Then I have a jQuery method that can find any server data tag: $(containingElement).serverData("loadScript"); // returns a jQuery like array of the decoded json objects.

    The client may look something like this:

    var script = $(containingelement").serverData("loadScript");
    $.getScript(script.url, function () {
        // script has been loaded - can do stuff with it now
    });
    

    This technique is great for user controls or scripts that need to be loaded within ajax loaded content. The version I wrote is a little more involved handling caching scripts so they load only once per full page load and contain callbacks and jQuery triggers so you can hook into it when it is ready.

    If anyone is interested in the full version of this (from MVC to jQuery extension) I would be happy to show off this technique in more detail. Otherwise - hopes it gives someone a new way of approaching this tricky problem.

    0 讨论(0)
  • 2020-12-02 06:38

    So, this is kind of an old question, but I found it while trying to solve a recent issue. I asked a question and answered it here. Here is a copy of that answer. It is similar to the OP's answer, but avoids using TempData.

    One solution is to implement an Html helper extension function which will only load a script once. See below. (this can work for CSS and other included files, too).

    Implement an extension for the HtmlHelper class and a private backing class as a singleton per HttpContext.

    public static class YourHtmlHelperExtensionClass 
    {
        private class TagSrcAttrTracker
        {
            private TagSrcAttrTracker() { }
    
            public Dictionary<string, string> sources { get; } = new Dictionary<string, string>();
    
            public static TagSrcAttrTrackerInstance {
                get {
                    IDictionary items = HttpContext.Current.Items;
                    const string instanceName = "YourClassInstanceNameMakeSureItIsUniqueInThisDictionary";
    
                    if(!items.Contains(instanceName)) 
                        items[instanceName] = new TagSrcAttrTracker();
    
                    return items[instanceName] as TagSrcAttrTracker;
                }
            }
        }
    
        public static MvcHtmlString IncludeScriptOnlyOnce(this HtmlHelper helper, string urlOfScript) 
        {
            if(TagSrcAttrTracker.Instance.sources.ContainsKey(urlOfScript))
                return null;
    
            TagSrcAttrTracker.Instance.sources[urlOfScript] = urlOfScript;
    
            TagBuilder script = new TagBuilder("script");
            scriptTag.MergeAttribute("src", urlOfScript);
    
            return MvcHtmlString.Create(script.ToString());
        }
    }
    

    Then, separate the JavaScript and other code into separate files.

    Example .js file contents

    class MyClass{
        myFunction() {
            constructor(divId){
                this._divId = divId
            }
    
            doSomething() {
                // do something with a div with id == divId
            }
        }
    }
    

    Example .cshtml file contents for partial view

    <link rel="stylesheet" type="text/css" href="~/Content/CustomCSS/MyPartialView.css"/>
    
    <div id="@ViewBag.id">
        Some content!  Yay!
    </div>
    
    @Html.IncludeScriptOnlyOnce("/Scripts/CustomScripts/MyPartialView.js")
    

    Example .cshtml file that consumes the partial view

    ...
    <body>
        <h1>Here is some content!</h1>
        @Html.Partial("/Views/MyPartial.cshtml", new ViewDataDictionary() { { "id", "id_1"} })
        @Html.Partial("/Views/MyPartial.cshtml", new ViewDataDictionary() { { "id", "id_2"} })
        @Html.Partial("/Views/MyPartial.cshtml", new ViewDataDictionary() { { "id", "id_3"} })
    </body>
    <script>
    $().ready(
        const id1Functionality = new MyClass("id_1") // forgive the poor naming :-)
        const id2Functionality = new MyClass("id_3")
        const id3Functionality = new MyClass("id_2")
    
        id1Functionality.doSomething();
        id2Functionality.doSomething();
        id3Functionality.doSomething();
    )
    </script>
    

    The partial view may have been included more than once and the JavaScript is packaged with the partial view, but the .js file is only included in the page once, hence no complaining by the browser that MyClass was declared more than once.

    0 讨论(0)
  • 2020-12-02 06:45

    Seems very similar to this question: Linking JavaScript Libraries in User Controls

    I'll repost my answer that that question here.

    I would definitely advise against putting them inside partials for exactly the reason you mention. There is a high chance that one view could pull in two partials that both have references to the same js file. You've also got the performance hit of loading js before loading the rest of the html.

    I don't know about best practice but I choose to include any common js files inside the masterpage and then define a separate ContentPlaceHolder for some additional js files that are specific to a particular or small number of views.

    Here's an example master page - it's pretty self explanatory.

    <%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>
    <head runat="server">
        ... BLAH ...
        <asp:ContentPlaceHolder ID="AdditionalHead" runat="server" />
        ... BLAH ...
        <%= Html.CSSBlock("/styles/site.css") %>
        <%= Html.CSSBlock("/styles/ie6.css", 6) %>
        <%= Html.CSSBlock("/styles/ie7.css", 7) %>
        <asp:ContentPlaceHolder ID="AdditionalCSS" runat="server" />
    </head>
    <body>
        ... BLAH ...
        <%= Html.JSBlock("/scripts/jquery-1.3.2.js", "/scripts/jquery-1.3.2.min.js") %>
        <%= Html.JSBlock("/scripts/global.js", "/scripts/global.min.js") %>
        <asp:ContentPlaceHolder ID="AdditionalJS" runat="server" />
    </body>
    

    Html.CSSBlock & Html.JSBlock are obviously my own extensions but again, they are self explanatory in what they do.

    Then in say a SignUp.aspx view I would have

    <asp:Content ID="signUpContent" ContentPlaceHolderID="AdditionalJS" runat="server">
        <%= Html.JSBlock("/scripts/pages/account.signup.js", "/scripts/pages/account.signup.min.js") %>
    </asp:Content>
    

    HTHs, Charles

    Ps. Here is a follow up question I asked about minifying and concatenating js files: Concatenate & Minify JS on the fly OR at build time - ASP.NET MVC

    EDIT: As requested on my other answer, my implementation of .JSBlock(a, b) as requested

    public static MvcHtmlString JSBlock(this HtmlHelper html, string fileName)
    {
        return html.JSBlock(fileName, string.Empty);
    }
    
    public static MvcHtmlString JSBlock(this HtmlHelper html, string fileName, string releaseFileName)
    {
        if (string.IsNullOrEmpty(fileName))
            throw new ArgumentNullException("fileName");
    
        string jsTag = string.Format("<script type=\"text/javascript\" src=\"{0}\"></script>",
                                     html.MEDebugReleaseString(fileName, releaseFileName));
    
        return MvcHtmlString.Create(jsTag);
    }
    

    And then where the magic happens...

        public static MvcHtmlString MEDebugReleaseString(this HtmlHelper html, string debugString, string releaseString)
        {
            string toReturn = debugString;
    #if DEBUG
    #else
            if (!string.IsNullOrEmpty(releaseString))
                toReturn = releaseString;
    #endif
            return MvcHtmlString.Create(toReturn);
        }
    
    0 讨论(0)
提交回复
热议问题