web-dev-qa-db-fra.com

Inclure le fichier JavaScript dans les vues partielles

Je me demande quelle est la meilleure pratique pour inclure des fichiers javascript dans des vues partielles. Une fois rendu, cela se retrouvera sous la forme d’une balise d’inclusion js au milieu du code HTML de ma page. De mon point de vue, ce n'est pas une bonne façon de faire cela. Ils appartiennent à la balise head et n'empêchent donc pas le navigateur de rendre le code HTML en une fois.

Un exemple: J'utilise un plugin jquery picturegallery dans une vue partielle 'PictureGallery', cette vue partielle étant utilisée sur plusieurs pages. Ce plugin ne doit être chargé que lorsque cette vue est utilisée et Je ne veux pas avoir besoin de savoir quels plugins chaque vue partielle utilise ...

Merci pour vos réponses.

69
Peter

Cela ressemble beaucoup à cette question: Liaison de bibliothèques JavaScript dans les contrôles utilisateur

Je vais republier ma réponse que cette question ici.

Je conseillerais certainement de ne pas les mettre dans des partiels pour la raison que vous mentionnez. Il y a de fortes chances qu'une vue puisse extraire deux partiels qui ont tous deux des références au même fichier js. Vous avez également la performance de charger js avant de charger le reste du code HTML.

Je ne connais pas les meilleures pratiques, mais j'ai choisi d'inclure tous les fichiers js courants dans la page maître, puis de définir un ContentPlaceHolder distinct pour certains fichiers js supplémentaires spécifiques à un nombre réduit ou particulier de vues.

Voici un exemple de page maître, assez explicite.

<%@ 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 sont évidemment mes propres extensions, mais encore une fois, ils sont explicites dans ce qu'ils font.

Ensuite, dans une vue SignUp.aspx, j'aurais

<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. Voici une question complémentaire que j'ai posée à propos de la minification et de la concaténation de fichiers js: Concaténer et minimiser JS à la volée OR au moment de la construction - ASP.NET MVC

EDIT: Comme demandé dans mon autre réponse, mon implémentation de .JSBlock (a, b) comme demandé

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);
}

Et puis où la magie se produit ...

    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);
    }
28
Charlino

Aujourd'hui, j'ai créé ma propre solution qui convient parfaitement. Que ce soit un bon design ou non, c'est à vous de décider, mais je pense que je devrais le partager de toute façon!

Ci-dessous ma classe HtmlExtensions qui vous permet de le faire dans votre page principale: 

<%=Html.RenderJScripts() %>

Ma classe HtmlExtensions: 

public static class HtmlExtensions
{
    private const string JSCRIPT_VIEWDATA = "__js";

    #region Javascript Inclusions

    public static void JScript(this HtmlHelper html, string scriptLocation)
    {
        html.JScript(scriptLocation, string.Empty);
    }

    public static void JScript(this HtmlHelper html, string scriptLocationDebug, string scriptLocationRelease)
    {
        if (string.IsNullOrEmpty(scriptLocationDebug))
            throw new ArgumentNullException("fileName");

        string jsTag = "<script type=\"text/javascript\" src=\"{0}\"></script>";

#if DEBUG
        jsTag = string.Format(jsTag, scriptLocationDebug);
#else
        jsTag = string.Format(jsTag, !string.IsNullOrEmpty(scriptLocationRelease) ? scriptLocationRelease : scriptLocationDebug);
#endif

        registerJScript(html, jsTag);
    }

    public static MvcHtmlString RenderJScripts(this HtmlHelper html)
    {
        List<string> jscripts = html.ViewContext.TempData[JSCRIPT_VIEWDATA] as List<string>;
        string result = string.Empty; ;
        if(jscripts != null)
        {
            result = string.Join("\r\n", jscripts);
        }
        return MvcHtmlString.Create(result);
    }

    private static void registerJScript(HtmlHelper html, string jsTag)
    {
        List<string> jscripts = html.ViewContext.TempData[JSCRIPT_VIEWDATA] as List<string>;
        if(jscripts == null) jscripts = new List<string>();

        if(!jscripts.Contains(jsTag))
            jscripts.Add(jsTag);

        html.ViewContext.TempData[JSCRIPT_VIEWDATA] = jscripts;
    }

    #endregion

}

Que se passe-t-il?
La classe ci-dessus étendra HtmlHelper avec des méthodes pour ajouter des liens javascript à une collection en cours de stockage par la collection HtmlHelper.ViewContext.TempData. À la fin de la page principale, je mets la <%=Html.RenderJScripts() %> qui bouclera la collection de jscripts à l'intérieur du HtmlHelper.ViewContext.TempData et les rendra à la sortie.

Cependant, il y a un inconvénient. Vous devez vous assurer de ne pas rendre les scripts avant de les avoir ajoutés. Si vous souhaitez faire cela pour des liens css par exemple, cela ne fonctionnera pas car vous devez les placer dans la balise <head> de votre page et htmlhelper rendra la sortie avant même que vous ayez ajouté un lien.

1
Peter

Si vous souhaitez placer un script au bas de la page, vous devez vous assurer que le dom a été chargé avant toute tentative de manipulation. Ceci peut également être réalisé dans quelque chose comme le $ (document) .ready (rappel); Méthode jQuery.

Je partage le point de vue de ne pas mettre JavaScript incorporé dans le code HTML. Au lieu de cela, j'utilise un assistant HTML pour créer une div vide à utiliser comme instruction de serveur. Le sig helper est Html.ServerData (nom de chaîne, données d'objet);

J'utilise cette méthode ServerData pour les instructions du serveur au client. La balise div le garde propre et l'attribut "data-" est valide html5.

Pour l'instruction loadScript, je peux faire quelque chose comme ceci dans mon ascx ou aspx:

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

Ou ajoutez un autre assistant pour faire cela qui a l'air un peu plus propre:

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

La sortie HTML serait:

<div name = "loadScript" data-server = "chaîne json codée">

Ensuite, j'ai une méthode jQuery qui peut trouver n'importe quelle balise de données du serveur: $ (ContainElement) .serverData ("loadScript"); // retourne un tableau jQuery ressemblant aux objets json décodés.

Le client peut ressembler à quelque chose comme ceci:

 var script = $ (contenant l'élément "). serverData (" loadScript "); 
 $. getScript (script.url, function () {
 // le script a été chargé - vous pouvez le gérer maintenant 
}); 

Cette technique est idéale pour les contrôles utilisateur ou les scripts qui doivent être chargés dans le contenu chargé ajax. La version que j'ai écrite est un peu plus complexe à gérer les scripts de mise en cache, ils ne se chargent donc qu'une seule fois par page entière et contiennent des callbacks et des déclencheurs jQuery afin que vous puissiez y accéder quand il est prêt.

Si quelqu'un est intéressé par la version complète de ceci (de MVC à l'extension jQuery), je serais heureux de montrer cette technique plus en détail. Autrement, j'espère que cela donnera à quelqu'un une nouvelle façon d'aborder ce problème épineux.

1
jhorback

hejdig.

Jouant avec Aspnetmvc3, j’ai décidé, pour l’instant, d’inclure mon fichier javascript dans la partie

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

Ce fichier js est alors spécifique à mon fichier /user/List.schtml.

/DE

0
LosManos

Cela semble être une question similaire (bien que pas tout à fait). Est-ce une mauvaise pratique de renvoyer des vues partielles contenant du javascript?

0
Allen Rice

Ma préférence sera de créer une page plugin.master qui hérite de votre site principal. L'idée est que vous insérez ces plugins dans plugin.master et créez les 8 pages environ qui utiliseront cette vue partielle pour hériter de plugin.master.

0
Pita.O

L'approche privilégiée consiste à mettre les scripts en bas , cependant, si vous ne pouvez pas l'éviter, il est raisonnable de les mettre au milieu.

Les navigateurs chargent généralement les différents éléments de la page en parallèle. Toutefois, pendant le téléchargement du fichier Javascript, le navigateur ne télécharge aucun autre élément de la page en parallèle tant que le téléchargement n'est pas terminé. Cela signifie que vos images et tout ce qui ne sera pas à attendre est donc généralement considéré comme préférable de déplacer les scripts en bas, mais si votre script est petit, je ne m'en soucierais pas.

0
aleemb