Aggiungi file CSS o JavaScript alla testa di layout dalle viste o dalle viste parziali

Testate delle pagine di layout:

   

Una vista (AnotherView) dalle esigenze dell’applicazione:

  

e AnotherView ha una vista parziale (AnotherPartial) che richiede:

  

Domanda: Come possiamo aggiungere questi collegamenti ai file CSS Link AnotherView e AnotherPartial al capo Layout ?

RenderSection non è una buona idea perché AnotherPage può avere più di un partial. Aggiungere tutto il CSS alla testa non è utile perché cambierà dynamicmente (dipende da Anotherpages).

Disposizione:

    @ViewBag.Title    @if (IsSectionDefined("AddToHead")) { @RenderSection("AddToHead", required: false) } @RenderSection("AddToHeadAnotherWay", required: false)  

Vista:

 @model ProjectsExt.Models.DirectoryObject @section AddToHead{  } 

Aggiornamento : esempio di base disponibile su https://github.com/speier/mvcassetshelper

Stiamo utilizzando la seguente implementazione per aggiungere file JS e CSS nella pagina di layout.

Visualizza o PartialView:

 @{ Html.Assets().Styles.Add("/Dashboard/Content/Dashboard.css"); Html.Assets().Scripts.Add("/Dashboard/Scripts/Dashboard.js"); } 

Pagina di layout:

  @Html.Assets().Styles.Render()   ... @Html.Assets().Scripts.Render()  

Estensione HtmlHelper:

 public static class HtmlHelperExtensions { public static AssetsHelper Assets(this HtmlHelper htmlHelper) { return AssetsHelper.GetInstance(htmlHelper); } } public class AssetsHelper { public static AssetsHelper GetInstance(HtmlHelper htmlHelper) { var instanceKey = "AssetsHelperInstance"; var context = htmlHelper.ViewContext.HttpContext; if (context == null) return null; var assetsHelper = (AssetsHelper)context.Items[instanceKey]; if (assetsHelper == null) context.Items.Add(instanceKey, assetsHelper = new AssetsHelper()); return assetsHelper; } public ItemRegistrar Styles { get; private set; } public ItemRegistrar Scripts { get; private set; } public AssetsHelper() { Styles = new ItemRegistrar(ItemRegistrarFormatters.StyleFormat); Scripts = new ItemRegistrar(ItemRegistrarFormatters.ScriptFormat); } } public class ItemRegistrar { private readonly string _format; private readonly IList _items; public ItemRegistrar(string format) { _format = format; _items = new List(); } public ItemRegistrar Add(string url) { if (!_items.Contains(url)) _items.Add(url); return this; } public IHtmlString Render() { var sb = new StringBuilder(); foreach (var item in _items) { var fmt = string.Format(_format, item); sb.AppendLine(fmt); } return new HtmlString(sb.ToString()); } } public class ItemRegistrarFormatters { public const string StyleFormat = ""; public const string ScriptFormat = ""; } 

Purtroppo, per impostazione predefinita non è ansible utilizzare la section come suggerito da un altro utente, poiché una section è disponibile solo per il child immediato di una View .

Ciò che funziona, tuttavia, è l’ implementazione e la ridefinizione della section in ogni vista , ovvero:

 section Head { @RenderSection("Head", false) } 

In questo modo ogni vista può implementare una sezione di testa, non solo i bambini immediati. Questo funziona solo parzialmente, specialmente con parziali multipli che iniziano i problemi (come hai menzionato nella tua domanda).

Quindi l’unica vera soluzione al tuo problema è usare ViewBag . Il migliore sarebbe probabilmente una raccolta (lista) separata per CSS e script. Affinché ciò funzioni, è necessario assicurarsi che l’ List utilizzato sia inizializzato prima dell’esecuzione di una qualsiasi delle viste. Quindi puoi fare cose come questa nella parte superiore di ogni vista / parziale (senza preoccuparti se il valore di Scripts o Styles è nullo:

 ViewBag.Scripts.Add("myscript.js"); ViewBag.Styles.Add("mystyle.css"); 

Nel layout è quindi ansible scorrere ciclicamente le raccolte e aggiungere gli stili in base ai valori List .

 @foreach (var script in ViewBag.Scripts) {  } @foreach (var style in ViewBag.Styles) {  } 

Penso che sia brutto, ma è l’unica cosa che funziona.

****** AGGIORNATO **** Dal momento in cui inizia a eseguire prima le viste interne e ad arrivare al layout e gli stili CSS sono a cascata, sarebbe probabilmente opportuno invertire l’elenco di stili tramite ViewBag.Styles.Reverse() .

In questo modo viene aggiunto per primo lo stile più esterno, che è in linea con il modo in cui funzionano i fogli di stile CSS.

Ho provato a risolvere questo problema.

La mia risposta è qui.

“DynamicHeader” – http://dynamicheader.codeplex.com/ , https://nuget.org/packages/DynamicHeader

Ad esempio, _Layout.cshtml è:

  @Html.DynamicHeader()  ... 

E puoi registrare i file .js e .css su “DynamicHeader” ovunque tu voglia.

Per exmaple, il blocco di codice in AnotherPartial.cshtm è:

 @{ DynamicHeader.AddSyleSheet("~/Content/themes/base/AnotherPartial.css"); DynamicHeader.AddScript("~/some/myscript.js"); } 

Quindi, l’output HTML finale è:

     ... 

Ho avuto un problema simile, e ho finito per applicare l’eccellente risposta di Kalman con il codice seguente (non abbastanza pulito, ma probabilmente più espansivo):

 namespace MvcHtmlHelpers { //http://stackoverflow.com/questions/5110028/add-css-or-js-files-to-layout-head-from-views-or-partial-views#5148224 public static partial class HtmlExtensions { public static AssetsHelper Assets(this HtmlHelper htmlHelper) { return AssetsHelper.GetInstance(htmlHelper); } } public enum BrowserType { Ie6=1,Ie7=2,Ie8=4,IeLegacy=7,W3cCompliant=8,All=15} public class AssetsHelper { public static AssetsHelper GetInstance(HtmlHelper htmlHelper) { var instanceKey = "AssetsHelperInstance"; var context = htmlHelper.ViewContext.HttpContext; if (context == null) {return null;} var assetsHelper = (AssetsHelper)context.Items[instanceKey]; if (assetsHelper == null){context.Items.Add(instanceKey, assetsHelper = new AssetsHelper(htmlHelper));} return assetsHelper; } private readonly List _styleRefs = new List(); public AssetsHelper AddStyle(string stylesheet) { _styleRefs.Add(stylesheet); return this; } private readonly List _scriptRefs = new List(); public AssetsHelper AddScript(string scriptfile) { _scriptRefs.Add(scriptfile); return this; } public IHtmlString RenderStyles() { ItemRegistrar styles = new ItemRegistrar(ItemRegistrarFormatters.StyleFormat,_urlHelper); styles.Add(Libraries.UsedStyles()); styles.Add(_styleRefs); return styles.Render(); } public IHtmlString RenderScripts() { ItemRegistrar scripts = new ItemRegistrar(ItemRegistrarFormatters.ScriptFormat, _urlHelper); scripts.Add(Libraries.UsedScripts()); scripts.Add(_scriptRefs); return scripts.Render(); } public LibraryRegistrar Libraries { get; private set; } private UrlHelper _urlHelper; public AssetsHelper(HtmlHelper htmlHelper) { _urlHelper = new UrlHelper(htmlHelper.ViewContext.RequestContext); Libraries = new LibraryRegistrar(); } } public class LibraryRegistrar { public class Component { internal class HtmlReference { internal string Url { get; set; } internal BrowserType ServeTo { get; set; } } internal List Styles { get; private set; } internal List Scripts { get; private set; } internal List RequiredLibraries { get; private set; } public Component() { Styles = new List(); Scripts = new List(); RequiredLibraries = new List(); } public Component Requires(params string[] libraryNames) { foreach (var lib in libraryNames) { if (!RequiredLibraries.Contains(lib)) { RequiredLibraries.Add(lib); } } return this; } public Component AddStyle(string url, BrowserType serveTo = BrowserType.All) { Styles.Add(new HtmlReference { Url = url, ServeTo=serveTo }); return this; } public Component AddScript(string url, BrowserType serveTo = BrowserType.All) { Scripts.Add(new HtmlReference { Url = url, ServeTo = serveTo }); return this; } } private readonly Dictionary _allLibraries = new Dictionary(); private List _usedLibraries = new List(); internal IEnumerable UsedScripts() { SetOrder(); var returnVal = new List(); foreach (var key in _usedLibraries) { returnVal.AddRange(from s in _allLibraries[key].Scripts where IncludesCurrentBrowser(s.ServeTo) select s.Url); } return returnVal; } internal IEnumerable UsedStyles() { SetOrder(); var returnVal = new List(); foreach (var key in _usedLibraries) { returnVal.AddRange(from s in _allLibraries[key].Styles where IncludesCurrentBrowser(s.ServeTo) select s.Url); } return returnVal; } public void Uses(params string[] libraryNames) { foreach (var name in libraryNames) { if (!_usedLibraries.Contains(name)){_usedLibraries.Add(name);} } } public bool IsUsing(string libraryName) { SetOrder(); return _usedLibraries.Contains(libraryName); } private List WalkLibraryTree(List libraryNames) { var returnList = new List(libraryNames); int counter = 0; foreach (string libraryName in libraryNames) { WalkLibraryTree(libraryName, ref returnList, ref counter); } return returnList; } private void WalkLibraryTree(string libraryName, ref List libBuild, ref int counter) { if (counter++ > 1000) { throw new System.Exception("Dependancy library appears to be in infinate loop - please check for circular reference"); } Component library; if (!_allLibraries.TryGetValue(libraryName, out library)) { throw new KeyNotFoundException("Cannot find a definition for the required style/script library named: " + libraryName); } foreach (var childLibraryName in library.RequiredLibraries) { int childIndex = libBuild.IndexOf(childLibraryName); if (childIndex!=-1) { //child already exists, so move parent to position before child if it isn't before already int parentIndex = libBuild.LastIndexOf(libraryName); if (parentIndex>childIndex) { libBuild.RemoveAt(parentIndex); libBuild.Insert(childIndex, libraryName); } } else { libBuild.Add(childLibraryName); WalkLibraryTree(childLibraryName, ref libBuild, ref counter); } } return; } private bool _dependenciesExpanded; private void SetOrder() { if (_dependenciesExpanded){return;} _usedLibraries = WalkLibraryTree(_usedLibraries); _usedLibraries.Reverse(); _dependenciesExpanded = true; } public Component this[string index] { get { if (_allLibraries.ContainsKey(index)) { return _allLibraries[index]; } var newComponent = new Component(); _allLibraries.Add(index, newComponent); return newComponent; } } private BrowserType _requestingBrowser; private BrowserType RequestingBrowser { get { if (_requestingBrowser == 0) { var browser = HttpContext.Current.Request.Browser.Type; if (browser.Length > 2 && browser.Substring(0, 2) == "IE") { switch (browser[2]) { case '6': _requestingBrowser = BrowserType.Ie6; break; case '7': _requestingBrowser = BrowserType.Ie7; break; case '8': _requestingBrowser = BrowserType.Ie8; break; default: _requestingBrowser = BrowserType.W3cCompliant; break; } } else { _requestingBrowser = BrowserType.W3cCompliant; } } return _requestingBrowser; } } private bool IncludesCurrentBrowser(BrowserType browserType) { if (browserType == BrowserType.All) { return true; } return (browserType & RequestingBrowser) != 0; } } public class ItemRegistrar { private readonly string _format; private readonly List _items; private readonly UrlHelper _urlHelper; public ItemRegistrar(string format, UrlHelper urlHelper) { _format = format; _items = new List(); _urlHelper = urlHelper; } internal void Add(IEnumerable urls) { foreach (string url in urls) { Add(url); } } public ItemRegistrar Add(string url) { url = _urlHelper.Content(url); if (!_items.Contains(url)) { _items.Add( url); } return this; } public IHtmlString Render() { var sb = new StringBuilder(); foreach (var item in _items) { var fmt = string.Format(_format, item); sb.AppendLine(fmt); } return new HtmlString(sb.ToString()); } } public class ItemRegistrarFormatters { public const string StyleFormat = ""; public const string ScriptFormat = ""; } } 

Il progetto contiene un metodo statico AssignAllResources:

 assets.Libraries["jQuery"] .AddScript("~/Scripts/jquery-1.10.0.min.js", BrowserType.IeLegacy) .AddScript("~/Scripts//jquery-2.0.1.min.js",BrowserType.W3cCompliant); /* NOT HOSTED YET - CHECK SOON .AddScript("//ajax.googleapis.com/ajax/libs/jquery/2.0.1/jquery.min.js",BrowserType.W3cCompliant); */ assets.Libraries["jQueryUI"].Requires("jQuery") .AddScript("//ajax.googleapis.com/ajax/libs/jqueryui/1.9.2/jquery-ui.min.js",BrowserType.Ie6) .AddStyle("//ajax.aspnetcdn.com/ajax/jquery.ui/1.9.2/themes/eggplant/jquery-ui.css",BrowserType.Ie6) .AddScript("//ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min.js", ~BrowserType.Ie6) .AddStyle("//ajax.aspnetcdn.com/ajax/jquery.ui/1.10.3/themes/eggplant/jquery-ui.css", ~BrowserType.Ie6); assets.Libraries["TimePicker"].Requires("jQueryUI") .AddScript("~/Scripts/jquery-ui-sliderAccess.min.js") .AddScript("~/Scripts/jquery-ui-timepicker-addon-1.3.min.js") .AddStyle("~/Content/jQueryUI/jquery-ui-timepicker-addon.css"); assets.Libraries["Validation"].Requires("jQuery") .AddScript("//ajax.aspnetcdn.com/ajax/jquery.validate/1.11.1/jquery.validate.min.js") .AddScript("~/Scripts/jquery.validate.unobtrusive.min.js") .AddScript("~/Scripts/mvcfoolproof.unobtrusive.min.js") .AddScript("~/Scripts/CustomClientValidation-1.0.0.min.js"); assets.Libraries["MyUtilityScripts"].Requires("jQuery") .AddScript("~/Scripts/GeneralOnLoad-1.0.0.min.js"); assets.Libraries["FormTools"].Requires("Validation", "MyUtilityScripts"); assets.Libraries["AjaxFormTools"].Requires("FormTools", "jQueryUI") .AddScript("~/Scripts/jquery.unobtrusive-ajax.min.js"); assets.Libraries["DataTables"].Requires("MyUtilityScripts") .AddScript("//ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/jquery.dataTables.min.js") .AddStyle("//ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/css/jquery.dataTables.css") .AddStyle("//ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/css/jquery.dataTables_themeroller.css"); assets.Libraries["MvcDataTables"].Requires("DataTables", "jQueryUI") .AddScript("~/Scripts/jquery.dataTables.columnFilter.min.js"); assets.Libraries["DummyData"].Requires("MyUtilityScripts") .AddScript("~/Scripts/DummyData.js") .AddStyle("~/Content/DummyData.css"); 

nella pagina _layout

 @{ var assets = Html.Assets(); CurrentResources.AssignAllResources(assets); Html.Assets().RenderStyles() }  ... @Html.Assets().RenderScripts()  

e nelle parziali e nelle viste

 Html.Assets().Libraries.Uses("DataTables"); Html.Assets().AddScript("~/Scripts/emailGridUtilities.js"); 

È ansible definire la sezione mediante il metodo RenderSection nel layout.

disposizione

   @RenderSection("heads", required: false)  

Quindi puoi includere i file css nell’area della sezione nella tua vista, ad eccezione della vista parziale .

La sezione funziona in vista, ma non funziona nella visualizzazione parziale in base alla progettazione .

  @section heads {  } 

Se si desidera veramente utilizzare l’area della sezione nella vista parziale, è ansible seguire l’articolo per ridefinire il metodo RenderSection.

Rasoio, layout nidificati e sezioni ridefinite – Marcin su ASP.NET

Prova la soluzione pronta all’uso (ASP.NET MVC 4 o versioni successive):

 @{ var bundle = BundleTable.Bundles.GetRegisteredBundles().First(b => b.Path == "~/js"); bundle.Include("~/Scripts/myFile.js"); } 

Per quelli di noi che utilizzano ASP.NET MVC 4 – questo potrebbe essere utile.

Innanzitutto, ho aggiunto una class BundleConfig nella cartella App_Start.

Ecco il mio codice che ho usato per crearlo:

 using System.Web.Optimization; public class BundleConfig { public static void RegisterBundles(BundleCollection bundles) { bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/SiteMaster.css")); } } 

Secondo, ho registrato la class BundleConfig nel file Global.asax:

 protected void Application_Start() { BundleConfig.RegisterBundles(BundleTable.Bundles); } 

In terzo luogo, ho aggiunto gli helper di stile al mio file CSS:

 /* Styles for validation helpers */ .field-validation-error { color: red; font-weight: bold; } .field-validation-valid { display: none; } input.input-validation-error { border: 1px solid #e80c4d; } input[type="checkbox"].input-validation-error { border: 0 none; } .validation-summary-errors { color: #e80c4d; font-weight: bold; font-size: 1.1em; } .validation-summary-valid { display: none; } 

Finalmente ho usato questa syntax in qualsiasi vista:

 @Styles.Render("~/Content/css") 

Ecco un plugin NuGet chiamato Cassette , che tra le altre cose offre la possibilità di fare riferimento a script e stili in partial.

Anche se ci sono un certo numero di configurazioni disponibili per questo plugin, il che lo rende molto flessibile. Ecco il modo più semplice per fare riferimento a file script o fogli di stile:

 Bundles.Reference("scripts/app"); 

Secondo la documentazione :

Le chiamate a Reference possono apparire ovunque in una pagina, layout o vista parziale.

L’argomento path può essere uno dei seguenti:

  • Un percorso in bundle
  • Un percorso di asset: viene fatto riferimento all’intero pacchetto contenente questo asset
  • Un URL

Ho scritto un semplice wrapper che consente di registrare stili e script in ogni vista parziale in modo dinamico nel tag head.

Si basa sul jsakamoto di DynamicHeader, ma presenta alcuni miglioramenti e ritocchi delle prestazioni.

È molto facile da usare e versatile.

L’utilizzo:

 @{ DynamicHeader.AddStyleSheet("/Content/Css/footer.css", ResourceType.Layout); DynamicHeader.AddStyleSheet("/Content/Css/controls.css", ResourceType.Infrastructure); DynamicHeader.AddScript("/Content/Js/Controls.js", ResourceType.Infrastructure); DynamicHeader.AddStyleSheet("/Content/Css/homepage.css"); } 

Puoi trovare il codice completo, le spiegazioni e gli esempi all’interno: Aggiungi stili e script dynamicmente al tag principale