从视图或部分视图中将CSS或JavaScript文件添加到布局头部
布局页面头:
<head> <link href="@Url.Content("~/Content/themes/base/Site.css")" rel="stylesheet" type="text/css" /> </head>
应用程序的View(AnotherView)需要:
<link href="@Url.Content("~/Content/themes/base/AnotherPage.css")" rel="stylesheet" type="text/css" />
AnotherView有一个局部视图(AnotherPartial),它需要:
<link href="@Url.Content("~/Content/themes/base/AnotherPartial.css")" rel="stylesheet" type="text/css" />
问题:我们怎样才能把这些CSS文件的链接AnotherView和AnotherPartial链接添加到Layout头 ?
RenderSection不是一个好主意,因为AnotherPage可以有多个Partial。 将所有CSS添加到头是没有用的,因为它会改变dynamic(这取决于Anotherpages)。
布局:
<html> <head> <meta charset="utf-8" /> <title>@ViewBag.Title</title> <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" /> <script src="@Url.Content("~/Scripts/jquery-1.6.2.min.js")" type="text/javascript"></script> <script src="@Url.Content("~/Scripts/modernizr-2.0.6-development-only.js")" type="text/javascript"></script> @if (IsSectionDefined("AddToHead")) { @RenderSection("AddToHead", required: false) } @RenderSection("AddToHeadAnotherWay", required: false) </head>
视图:
@model ProjectsExt.Models.DirectoryObject @section AddToHead{ <link href="@Url.Content("~/Content/Upload.css")" rel="stylesheet" type="text/css" /> }
更新 : https : //github.com/speier/mvcassetshelper提供的基本示例
我们使用下面的实现将JS和CSS文件添加到布局页面中。
查看或部分查看:
@{ Html.Assets().Styles.Add("/Dashboard/Content/Dashboard.css"); Html.Assets().Scripts.Add("/Dashboard/Scripts/Dashboard.js"); }
布局页面:
<head> @Html.Assets().Styles.Render() </head> <body> ... @Html.Assets().Scripts.Render() </body>
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<string> _items; public ItemRegistrar(string format) { _format = format; _items = new List<string>(); } 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 = "<link href=\"{0}\" rel=\"stylesheet\" type=\"text/css\" />"; public const string ScriptFormat = "<script src=\"{0}\" type=\"text/javascript\"></script>"; }
不幸的是,这是不可能的默认情况下使用section
作为另一个用户build议,因为一个section
只适用于一个View
的直接child
。
然而,在每个视图中实施和重新定义该section
是有效的 ,这意味着:
section Head { @RenderSection("Head", false) }
这样,每个视图都可以实现一个头部,而不仅仅是直接的孩子。 这只是部分作用,特别是多重局部麻烦开始(正如你在你的问题中提到的)。
所以唯一真正的解决scheme是使用ViewBag
。 最好的可能是CSS和脚本的单独集合(列表)。 为此,您需要确保在执行任何视图之前,使用的List
已经初始化。 然后,您可以在每个视图/部分顶部执行此类操作(而不必关心“ Scripts
或Styles
值是否为空:
ViewBag.Scripts.Add("myscript.js"); ViewBag.Styles.Add("mystyle.css");
在布局中,您可以遍历集合并根据List
的值添加样式。
@foreach (var script in ViewBag.Scripts) { <script type="text/javascript" src="@script"></script> } @foreach (var style in ViewBag.Styles) { <link href="@style" rel="stylesheet" type="text/css" /> }
我认为这是丑陋的,但它是唯一可行的。
****** UPDATE ****由于它首先开始执行内部视图,并且按照布局工作,CSS样式是级联的,所以通过ViewBag.Styles.Reverse()
。
这样,最外层的样式首先被添加,这与CSS样式表的工作方式是一致的。
我试图解决这个问题。
我的答案在这里。
“DynamicHeader” – http://dynamicheader.codeplex.com/,https://nuget.org/packages/DynamicHeader
例如,_Layout.cshtml是:
<head> @Html.DynamicHeader() </head> ...
而且,您可以将.js和.css文件注册到“DynamicHeader” 任意位置 。
例如,AnotherPartial.cshtm中的代码块是:
@{ DynamicHeader.AddSyleSheet("~/Content/themes/base/AnotherPartial.css"); DynamicHeader.AddScript("~/some/myscript.js"); }
那么,最终输出的HTML是:
<html> <link href="/myapp/Content/themes/base/AnotherPartial.css" .../> <script src="/myapp/some/myscript.js" ...></script> </html> ...
我有一个类似的问题,并最终应用卡尔曼的下面的代码(不太整洁,但可以说更可扩展)的优秀答案:
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<string> _styleRefs = new List<string>(); public AssetsHelper AddStyle(string stylesheet) { _styleRefs.Add(stylesheet); return this; } private readonly List<string> _scriptRefs = new List<string>(); 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<HtmlReference> Styles { get; private set; } internal List<HtmlReference> Scripts { get; private set; } internal List<string> RequiredLibraries { get; private set; } public Component() { Styles = new List<HtmlReference>(); Scripts = new List<HtmlReference>(); RequiredLibraries = new List<string>(); } 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<string, Component> _allLibraries = new Dictionary<string, Component>(); private List<string> _usedLibraries = new List<string>(); internal IEnumerable<string> UsedScripts() { SetOrder(); var returnVal = new List<string>(); foreach (var key in _usedLibraries) { returnVal.AddRange(from s in _allLibraries[key].Scripts where IncludesCurrentBrowser(s.ServeTo) select s.Url); } return returnVal; } internal IEnumerable<string> UsedStyles() { SetOrder(); var returnVal = new List<string>(); 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<string> WalkLibraryTree(List<string> libraryNames) { var returnList = new List<string>(libraryNames); int counter = 0; foreach (string libraryName in libraryNames) { WalkLibraryTree(libraryName, ref returnList, ref counter); } return returnList; } private void WalkLibraryTree(string libraryName, ref List<string> 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<string> _items; private readonly UrlHelper _urlHelper; public ItemRegistrar(string format, UrlHelper urlHelper) { _format = format; _items = new List<string>(); _urlHelper = urlHelper; } internal void Add(IEnumerable<string> 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 = "<link href=\"{0}\" rel=\"stylesheet\" type=\"text/css\" />"; public const string ScriptFormat = "<script src=\"{0}\" type=\"text/javascript\"></script>"; } }
该项目包含一个静态的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/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/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/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/jquery.dataTables/1.9.4/jquery.dataTables.min.js") .AddStyle("ajax/jquery.dataTables/1.9.4/css/jquery.dataTables.css") .AddStyle("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");
在_layout页面
@{ var assets = Html.Assets(); CurrentResources.AssignAllResources(assets); Html.Assets().RenderStyles() } </head> ... @Html.Assets().RenderScripts() </body>
并在部分(S)和意见
Html.Assets().Libraries.Uses("DataTables"); Html.Assets().AddScript("~/Scripts/emailGridUtilities.js");
尝试开箱即用的解决scheme(ASP.NET MVC 4或更高版本):
@{ var bundle = BundleTable.Bundles.GetRegisteredBundles().First(b => b.Path == "~/js"); bundle.Include("~/Scripts/myFile.js"); }
对于我们这些使用ASP.NET MVC 4的人来说 – 这可能会有所帮助。
首先,我在App_Start文件夹中添加了一个BundleConfig类。
这是我用来创build它的代码:
using System.Web.Optimization; public class BundleConfig { public static void RegisterBundles(BundleCollection bundles) { bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/SiteMaster.css")); } }
其次,我在Global.asax文件中注册了BundleConfig类:
protected void Application_Start() { BundleConfig.RegisterBundles(BundleTable.Bundles); }
第三,我添加了样式助手到我的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; }
最后,我在任何View中使用了这个语法:
@Styles.Render("~/Content/css")
这是一个名为Cassette的NuGet插件,除此之外,它还提供了引用部分内容的脚本和样式的function。
虽然这个插件有许多可用的configuration ,这使得它非常灵活。 这是引用脚本或样式表文件最简单的方法:
Bundles.Reference("scripts/app");
根据文件 :
调用
Reference
可以出现在页面,布局或局部视图中的任何位置。path参数可以是以下之一:
- 捆绑path
- 资产path – 引用包含此资产的整个捆绑包
- 一个URL
我写了一个简单的包装器,允许您在每个局部视图中dynamic注册样式和脚本到头标签中。
它基于DynamicHeader jsakamoto,但它有一些性能改进和调整。
这是非常容易使用,多function。
用法:
@{ 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"); }
你可以在里面find完整的代码,解释和例子: dynamic添加样式和脚本到头标签
您可以在布局中通过RenderSection方法定义该部分。
布局
<head> <link href="@Url.Content("~/Content/themes/base/Site.css")" rel="stylesheet" type="text/css" /> @RenderSection("heads", required: false) </head>
然后你可以在你的视图中的部分区域中包含你的css文件, 除了部分视图 。
该部分工作, 但不能在部分视图devise工作 。
<!--your code --> @section heads { <link href="@Url.Content("~/Content/themes/base/AnotherPage.css")" rel="stylesheet" type="text/css" /> }
如果您真的想在局部视图中使用截面区域,可以按照文章重新定义RenderSection方法。
Razor,嵌套布局和重新定义的部分 – Marcin On ASP.NET