Добавить ссылки CSS на ‹head› страницы из частичного просмотра

Есть ли способ добавить ссылки CSS на страницу из частичного просмотра, и отобразить их в <head> страницы (в соответствии с требованиями спецификация HTML 4.01)?


person kristian    schedule 17.11.2010    source источник
comment
На ваш вопрос уже был дан ответ несколько раз, stackoverflow.com/questions/912755/ & stackoverflow.com/questions/885990/. Говорим ли мы в этом контексте о css или js, на самом деле не имеет значения.   -  person Pauli Østerø    schedule 18.11.2010
comment
@BurningIce - вы абсолютно правы, тип ресурса значения не имеет. Вопросы, на которые вы ссылаетесь, имеют один и тот же принятый ответ, который не работает для частичных представлений, поскольку они не могут использовать элементы управления asp: Content (сообщение об ошибке парсера: элементы управления содержимым должны быть элементами управления верхнего уровня на странице содержимого или вложенным эталонная страница, которая ссылается на эталонную страницу.) Или я что-то упустил?   -  person kristian    schedule 18.11.2010
comment
Хммм интересный момент. Я думаю, единственный реальный способ сделать это - разделить ваш скрипт / CSS на их собственные частичные представления. Затем визуализируйте партиал в asp: Content для раздела head. Это действительно все, о чем я могу думать.   -  person Chev    schedule 18.11.2010
comment
Хороший момент, я пропустил тот факт, что вы используете частичные представления.   -  person Pauli Østerø    schedule 18.11.2010


Ответы (6)


Если вы используете MVC3 и Razor, лучший способ добавить постраничные элементы в ваш раздел: 1) Вызвать RenderSection () на странице макета 2) Объявить соответствующий раздел на дочерних страницах:

/Views/Shared/_Layout.cshtml:

<head>
    <!-- ... Rest of your head section here ... ->
    @RenderSection("HeadArea")
</head>

/Views/Entries/Index.cshtml:

@section HeadArea {
    <link rel="Stylesheet" type="text/css" href="/Entries/Entries.css" />
}

Результирующая HTML-страница затем включает раздел, который выглядит следующим образом:

<head>
    <!-- ... Rest of your head section here ... ->
    <link rel="Stylesheet" type="text/css" href="/Entries/Entries.css" />
<head>
person Rich Turner    schedule 13.02.2011
comment
Ваше решение мне помогло. Спасибо! - person Evgeniy Labunskiy; 07.05.2011
comment
@Richard, то, что вы здесь описываете, не нацелено на проблему OP, он говорил о частичном представлении, в то время как _Layout.cshtml - это макет, а не частичное представление (то есть для экземпляров, включенных в Index.cshtml, и он хочет правильно отобразить сценарий в тег <head> _layout.cshtml. - person Shimmy Weitzhandler; 13.11.2012
comment
Если не все представления имеют HeadArea, те, у которых его нет, выдадут ошибку. Чтобы этого избежать, используйте вместо этого @RenderSection("HeadArea", required:false) в _Layout.cshtml. - person Leonard AB; 15.05.2019

Вы также можете использовать элементы управления Telerik с открытым исходным кодом для MVC и сделать что-то вроде:

<%= Html.Telerik().StyleSheetRegistrar()
                  .DefaultGroup(group => group
                     .Add("stylesheet.css"));

в головной части и

<%= Html.Telerik().ScriptRegistrar()
                  .DefaultGroup(group => group
                     .Add("script.js"));

в разделе скриптов внизу вашей страницы.

И вы можете продолжать добавлять сценарии в любое представление или частичное представление, и они должны работать.

Если вы не хотите использовать компонент, вы всегда можете вдохновить себя оттуда и сделать что-то более индивидуальное.

О, с Telerik у вас также есть возможности комбинирования и сжатия скриптов.

person sirrocco    schedule 18.11.2010
comment
+1, мне нравится это решение. Хотя мне любопытно узнать, как Telerik ведет свой бизнес. Я мог бы пойти взглянуть на это. - person Chev; 19.11.2010

У вас может быть частичная загрузка представления в блоке javascript, который опускается в стиле до головы, но это было бы глупо, учитывая, что вы, вероятно, хотите, чтобы блок javascript в разделе заголовка по той же причине.

Однако недавно я обнаружил кое-что довольно крутое. Вы можете сериализовать частичное представление в строку и отправить его обратно клиенту как часть объекта JSON. Это позволяет вам передавать вместе с представлением и другие параметры.

Возврат представления как части объекта JSON

Вы можете захватить объект JSON с помощью JQuery и ajax и загрузить его с частичным представлением, и тогда другое свойство JSON может быть вашим блоком стиля. JQuery может проверить, вернули ли вы блок стиля, если да, то поместите его в раздел заголовка.

Что-то типа:

$.ajax(
{
     url: "your/action/method",
     data: { some: data },
     success: function(response)
     {
          $('#partialViewContainer).html(response.partialView);
          if (response.styleBlock != null)
               $('head').append(response.styleBlock);
     }
});
person Chev    schedule 18.11.2010
comment
Хорошо подумав, это сработает, но это зависит от того, включен ли у пользователя javascript (что вполне справедливо, если вы загружаете ресурсы сценария, но не так много для CSS). - person kristian; 18.11.2010

Вы можете использовать HttpModule для управления HTML-кодом ответа и перемещения любых ссылок CSS / скриптов в соответствующие места. Это не идеально, и я не уверен в последствиях для производительности, но кажется, что это единственный способ решить проблему без (а) решения на основе javascript или (б) работы против принципов MVC.

person kristian    schedule 18.11.2010

Другой подход, который противоречит принципам MVC, заключается в использовании ViewModel и ответе на событие Init на вашей странице для установки желаемого css / javascript (т.е. myViewModel.Css.Add (". Css") и визуализации в вашей голове содержимое css-коллекции на вашей модели просмотра.

Для этого вы создаете базовый класс модели представления, от которого наследуются все ваши модели, аля

public class BaseViewModel
{
    public string Css { get; set; }
}

На своей главной странице вы настроили его для использования этой модели просмотра

<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage<BaseViewModel>" %>

и в вашем разделе заголовка вы можете записать значение свойства Css

<head runat="server">
    <title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>
    <link href="../../Content/Site.css" rel="stylesheet" type="text/css" />

    <%= Model.Css %>
</head>

Теперь, в вашем частичном представлении, вам нужен этот код, который уродлив в MVC.

<script runat="server">
    protected override void OnInit(EventArgs e)
    {
        Model.Css = "hej";

        base.OnInit(e);
    }
</script>
person Pauli Østerø    schedule 18.11.2010
comment
хотя OP не упоминает запросы ajax для частичного, это, конечно, сработает, но только как часть стандартного запроса страницы. Я предполагаю, что задача состоит в том, чтобы заставить его работать для частичных просмотров независимо от того, вызывается ли он как часть одного запроса или как обновление ajax (что я не вижу, как он будет работать, если он не был введен в раздел заголовка через javascript) - person jim tollan; 18.11.2010
comment
Ой! Мне это совсем не нравится. Я бы предпочел нарушить протокол для хранения стилей в разделе заголовка, чем выбросить разделение задач в моем приложении MVC! - person Chev; 19.11.2010

Следующее будет работать, только если включен javascript. это маленький помощник, который я использую именно для упомянутого вами сценария:

// standard method - renders as defined in as(cp)x file
public static MvcHtmlString Css(this HtmlHelper html, string path)
{
    return html.Css(path, false);
}
// override - to allow javascript to put css in head
public static MvcHtmlString Css(this HtmlHelper html, 
                                string path, 
                                bool renderAsAjax)
{
    var filePath = VirtualPathUtility.ToAbsolute(path);

    HttpContextBase context = html.ViewContext.HttpContext;
    // don't add the file if it's already there
    if (context.Items.Contains(filePath))
        return null;

    // otherwise, add it to the context and put on page
    // this of course only works for items going in via the current
    // request and by this method
    context.Items.Add(filePath, filePath);

    // js and css function strings
    const string jsHead = "<script type='text/javascript'>";
    const string jsFoot = "</script>";
    const string jsFunctionStt = "$(function(){";
    const string jsFunctionEnd = "});";
    string linkText = string.Format("<link rel=\"stylesheet\" type=\"text/css\" href=\"{0}\"></link>", filePath);
    string jsBody = string.Format("$('head').prepend('{0}');", linkText);

    var sb = new StringBuilder();

    if (renderAsAjax)
    {
        // join it all up now
        sb.Append(jsHead);
        sb.AppendFormat("\r\n\t");
        sb.Append(jsFunctionStt);
        sb.AppendFormat("\r\n\t\t");
        sb.Append(jsBody);
        sb.AppendFormat("\r\n\t");
        sb.Append(jsFunctionEnd);
        sb.AppendFormat("\r\n");
        sb.Append(jsFoot);
    }
    else
    {
        sb.Append(linkText);
    }

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

использование:

<%=Html.Css("~/content/site.css", true) %>

работает для меня, хотя, как указано, только если включен javascript, что немного ограничивает его полезность.

person jim tollan    schedule 18.11.2010