Добавить файлы CSS или JavaScript в макет из представлений или частичных представлений
Головка макетов страниц:
<head>
<link href="@Url.Content("~/Content/themes/base/Site.css")"
rel="stylesheet" type="text/css" />
</head>
A 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 файлы Другие и другие альтернативные ссылки на макет?
RenderSection - это не очень хорошая идея, потому что у AnotherPage может быть более одного Partials. Добавить CSS в голову не полезно, потому что он изменится динамически (это зависит от других страниц).
Ответы
Ответ 1
Разметка:
<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" />
}
Ответ 2
Обновить: базовый пример доступен в https://github.com/speier/mvcassetshelper
Мы используем следующую реализацию для добавления файлов JS и CSS на страницу макета.
Просмотр или PartialView:
@{
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>";
}
Ответ 3
К сожалению, по умолчанию невозможно использовать section
в качестве другого пользователя, поскольку section
доступен только для непосредственного child
для View
.
Однако работает реализация и переопределение section
в каждом представлении, что означает:
section Head
{
@RenderSection("Head", false)
}
Таким образом, каждый вид может реализовать раздел главы, а не только непосредственные дети. Это работает частично, хотя, особенно с несколькими частицами, проблемы начинаются (как вы упомянули в своем вопросе).
Итак, единственное реальное решение вашей проблемы - использование ViewBag
. Лучшим, вероятно, будет отдельная коллекция (список) для CSS и скриптов. Для этого вам необходимо убедиться, что используемый List
инициализирован до того, как будет выполнено какое-либо из представлений. Затем вы можете делать такие вещи в верхней части каждого представления/частичного (без заботы, если значение Scripts
или Styles
равно null:
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.
Ответ 4
Я попытался решить эту проблему.
Мой ответ здесь.
"DynamicHeader" - http://dynamicheader.codeplex.com/, https://nuget.org/packages/DynamicHeader
Например, _Layout.cshtml:
<head>
@Html.DynamicHeader()
</head>
...
И вы можете зарегистрировать файлы .js и .css в "DynamicHeader" где угодно.
Для exmaple блок кода в 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>
...
Ответ 5
У меня была аналогичная проблема, и в итоге я применил превосходный ответ Калмана с приведенным ниже кодом (не совсем как аккуратный, но, возможно, более расширяемый):
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.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");
на странице _layout
@{
var assets = Html.Assets();
CurrentResources.AssignAllResources(assets);
Html.Assets().RenderStyles()
}
</head>
...
@Html.Assets().RenderScripts()
</body>
и в частичном (ых) и представлениях
Html.Assets().Libraries.Uses("DataTables");
Html.Assets().AddScript("~/Scripts/emailGridUtilities.js");
Ответ 6
Вы можете определить раздел методом RenderSection в макете.
Разметка
<head>
<link href="@Url.Content("~/Content/themes/base/Site.css")"
rel="stylesheet" type="text/css" />
@RenderSection("heads", required: false)
</head>
Затем вы можете включить ваши файлы css в области раздела в своем представлении , кроме частичного представления.
Этот раздел работает, , но не работает в частичном виде по дизайну.
<!--your code -->
@section heads
{
<link href="@Url.Content("~/Content/themes/base/AnotherPage.css")"
rel="stylesheet" type="text/css" />
}
Если вы действительно хотите использовать секцию области в частичном представлении, вы можете перейти к статье, чтобы переопределить метод RenderSection.
Razor, вложенные макеты и переопределенные разделы - Marcin On ASP.NET
Ответ 7
Попробуйте готовое решение (ASP.NET MVC 4 или новее):
@{
var bundle = BundleTable.Bundles.GetRegisteredBundles().First(b => b.Path == "~/js");
bundle.Include("~/Scripts/myFile.js");
}
Ответ 8
Для тех из нас, кто использует ASP.NET MVC 4 - это может быть полезно.
Сначала я добавил класс BundleConfig в папку App_Start.
Вот мой код, который я использовал для его создания:
using System.Web.Optimization;
public class BundleConfig
{
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/SiteMaster.css"));
}
}
Во-вторых, я зарегистрировал класс BundleConfig в файле Global.asax:
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;
}
Наконец, я использовал этот синтаксис в любом представлении:
@Styles.Render("~/Content/css")
Ответ 9
Вот NuGet плагин под названием Cassette, который, среди прочего, предоставляет вам возможность ссылаться на скрипты и стили в частичных файлах.
Хотя для этого плагина есть несколько конфигураций, что делает его очень гибким. Вот простейший способ обращения к файлам script или stylesheet:
Bundles.Reference("scripts/app");
Согласно документации:
Вызовы Reference
могут отображаться в любом месте на странице, макете или частичном представлении.
Аргумент path может быть одним из следующих:
- Путь связки
- Путь к ресурсам - ссылка на весь пакет, содержащий этот актив.
- URL
Ответ 10
Я написал простую оболочку, которая позволяет динамически регистрировать стили и скрипты в каждом частичном представлении в тег заголовка.
Он основан на динамическом размещении jsakamoto DynamicHeader, но он имеет некоторые улучшения производительности и настройки.
Он очень прост в использовании и универсален.
Использование:
@{
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");
}
Вы можете найти полный код, объяснения и примеры внутри:
Добавить стили и скрипты с динамическим заголовком