J'essaie de déplacer toutes mes inclusions javascript en bas de la page. J'utilise MVC avec Razor. J'ai écrit une méthode d'aide pour enregistrer des scripts. Il conserve les scripts dans l'ordre dans lequel ils sont enregistrés et exclut les dupes.

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

Et puis juste avant la balise de fermeture, je fais quelque chose comme ceci:

    @Html.RenderScripts()
</body>

Tout cela fonctionne bien si les scripts sont enregistrés sur une seule page. Si j'enregistre certains scripts dans ma mise en page et certains scripts dans ma vue intérieure, les choses tournent mal. Fondamentalement, la vue intérieure s'exécute avant la mise en page. Donc, même si les scripts de la vue intérieure dépendent des scripts de la vue extérieure, ils sont déjà enregistrés.

Donc, si j'ai _Master.cshstml et qu'il a

@{
   Html.RegisterScript("script1.js");
   Html.RegisterScript("script2.js");
}

Et puis j'ai InnerView.cshtml avec _Master.cshtml comme disposition et dans la vue que j'ai

@{
   Html.RegisterScript("script3.js");
}

Les scripts sont affichés dans cet ordre: script3, script1, script 2.

Existe-t-il un moyen de forcer l'exécution de la mise en page avant la vue intérieure? J'ai essayé de déplacer des choses partout et tout ce que la vue intérieure semble toujours exécuter en premier. Peut-être que cela est prévu? Si oui, quelle est la meilleure façon pour moi d'accomplir ce que j'essaie de faire?

7
Eric 4 nov. 2011 à 20:34

6 réponses

Meilleure réponse

J'ai fini par résoudre ce problème en gardant une trace des scripts par vue. En gros je garde un

Dictionary<string, SortedList<int, string>> registeredScripts;

Et un

 SortedList<int, string> viewOrder;

Chaque fois que j'enregistre un script, je passe le chemin du script et le nom de la vue (extrait de ViewDataContainer.ToString ()). Je garde la trace de l'ordre dans lequel j'ai vu les vues dans l'objet viewOrder. J'utilise ensuite le dictionnaire pour garder une trace des scripts par vue. La clé est le nom de la vue. Quand vient le temps de tout rendre, j'inverse la viewOrder SortedList <> et j'écris tous les scripts par vue. Ce qui est bien, c'est que les scripts sont classés par vue et que l'ordre d'affichage une fois inversé est correct.

J'ai fait un travail horrible en expliquant cela, mais pour des raisons de copyright je ne peux pas partager le code.

2
Eric 4 nov. 2011 à 19:02

En tant que solution précise pour les dépendances de script, vous pouvez fournir des méthodes d'assistance pour:

Spécifiez les dépendances

Html.RegisterScript("script3.js", depsOn: new string[] {"script1.js", "script2.js"});

Spécifiez la priorité relative:

Html.RegisterScript("script3.js", Position.Bottom);
Html.RegisterScript("script1.js", Position.Top);
Html.RegisterScript("script2.js", Position.Top);

De cette façon, vous avez le contrôle nécessaire dans la plupart des situations.

0
Alvaroma 29 mai 2012 à 14:26

Non, c'est l'ordre qu'ils exécutent, du plus interne au plus externe. Je recommanderais d'utiliser une sorte de collection LIFO (dernier entré, premier sorti) comme {{X0 }} pour conserver les scripts, puis les retirer de la pile pour les rendre; De cette façon, les scripts ajoutés en dernier, c'est-à-dire ceux de la mise en page, seront ceux qui seront rendus en premier.

MODIFIER

J'ai écrit un package de nuget qui gère les scripts de rendu des vues partielles et des modèles qui résout ce problème.

3
Russ Cam 26 mars 2014 à 09:20

Il n'y a aucun moyen de changer l'ordre dans lequel MVC rend les pages (pour autant que je sache), mais ce que vous pouvez essayer de faire est de mettre à jour la fonctionnalité de votre script de rendu pour indiquer quand une mise en page enregistre ses scripts. Ainsi, par exemple, votre mise en page peut être:

@{
   Html.StartLayoutScriptRegistration();
   Html.RegisterScript("script1.js");
   Html.RegisterScript("script2.js");
}

Cela déclencherait pour votre système que les scripts enregistrés après l'appel de StartLayoutScriptRegistration() devraient être rendus en premier, puis suivis des enregistrements de script de votre vue enregistrés avant l'appel de 'StartLayoutScriptRegistration ()'.

1
KallDrexx 4 nov. 2011 à 18:07

Le code placé dans les parties @section est toujours exécuté dans l'ordre que vous attendez, vous pouvez donc utiliser ce fait:

Dans votre _Master.cshtml, écrivez:

@{
   Html.RegisterScript("script1.js");
   Html.RegisterScript("script2.js");
}

@RenderSection("references", required: false)

Et dans votre InnerView.cshtml:

@section references {@{
       Html.RegisterScript("script3.js");
}}

Cela conduira à votre ordre d'inclusion souhaité: script1, script2, script3

Remarques: Étant donné que la section "références" ne comprendra qu'un seul bloc de code et aucune véritable sortie Html, vous pouvez placer la partie @RenderSection n'importe où dans _Master.cshtml. Cela fonctionnera également avec les dispositions imbriquées!

0
user1823768 23 mai 2013 à 11:13

Créez d'abord 2 assistants HTML. Un pour ajouter des scripts par priorité:

    public static MvcHtmlString AddScript(this HtmlHelper htmlHelper, string script, int executionSequence = int.MaxValue)
    {
        Dictionary<int, List<string>> scripts = new Dictionary<int, List<string>>();
        if (htmlHelper.ViewContext.HttpContext.Items["_scripts_"] != null)
        {
            scripts = htmlHelper.ViewContext.HttpContext.Items["_scripts_"] as Dictionary<int, List<string>>;
        }

        if (!scripts.ContainsKey(executionSequence))
        {
            scripts.Add(executionSequence, new List<string>());
        }
        string tag = string.Format("<script type=\"text/javascript\" src=\"{0}\"></script>", script);
        scripts[executionSequence].Add(tag);
        htmlHelper.ViewContext.HttpContext.Items["_scripts_"] = scripts;
        return MvcHtmlString.Empty;
    }

Et un pour écrire ces scripts dans votre vue:

    public static IHtmlString RenderScripts(this HtmlHelper htmlHelper)
    {
        StringBuilder sb = new StringBuilder();
        foreach (object key in htmlHelper.ViewContext.HttpContext.Items.Keys)
        {
            if (key.ToString() == "_scripts_")
            {
                Dictionary<int, List<string>> scripts = htmlHelper.ViewContext.HttpContext.Items[key] as Dictionary<int, List<string>>;
                foreach (int index in scripts.Keys.OrderBy(x => x))
                {
                    foreach (string script in scripts[index])
                    {
                        if (script != null)
                        {
                            sb.AppendLine(script);
                        }
                    }
                }
            }
        }

        return MvcHtmlString.Create(sb.ToString());
    }

Ajoutez ensuite les scripts à vos vues partielles:

@Html.AddScript("script2.js", 2)
@Html.AddScript("script1.js", 1)

Et enfin, restituez les scripts dans votre modèle Razor:

@Html.RenderScripts()

Les résultats seront triés par priorité et rendus dans les balises de script:

<script type="text/javascript" src="script1.js"></script>
<script type="text/javascript" src="script2.js"></script>
1
LaundroMatt 26 nov. 2011 à 17:58
8012658