问题 从局部视图向页面的添加CSS引用


有没有办法从局部视图添加CSS引用到页面, 并让它们在页面中呈现 <head> (根据要求) HTML 4.01规范)?


10453
2017-11-17 23:46


起源

您的问题已经回答了几次, stackoverflow.com/questions/912755/... & stackoverflow.com/questions/885990/...。在这种情况下我们是否谈论css或js并不重要。 - Pauli Østerø
@BurningIce - 你是绝对正确的,资源类型并不重要。您链接的问题具有相同的已接受答案,这对部分视图不起作用,因为它们无法使用asp:内容控件(分析器错误消息:内容控件必须是内容页面中的顶级控件或嵌套引用母版页的母版页。)或者我错过了什么? - kristian
嗯有趣的一点。我想唯一真正的方法是将你的脚本/ css分成他们自己的部分视图。然后在asp:Content中为head部分渲染部分。这就是我能想到的全部。 - Chev
好的,我确实想念你使用局部视图的事实。 - Pauli Østerø


答案:


如果您使用的是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>

5
2018-02-13 22:21



你的解决方案帮了我谢谢! - Evgeniy Labunskiy
@Richard,你在这里所描述的并不针对OP的问题,而是在讨论局部视图 _Layout.cshtml 是布局,而不是局部视图(对于包含在其中的实例) Index.cshtml,并希望将脚本直接呈现 _layout.cshtml的 <head> 标签。 - Shimmy


您还可以使用Telerik的开源控件来执行MVC,并执行以下操作:

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

在头部 和

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

在页面底部的脚本部分。

您可以继续在任何视图或部分视图上添加脚本,它们应该可以工作。

如果您不想使用该组件,您可以随时从那里激发自己,并做一些更自定义的事情。

哦,对于Telerik,您还可以选择组合和压缩脚本。


4
2017-11-18 13:11



+1,我喜欢这个解决方案。虽然我很想知道Telerik如何做到这一点。我可能会去看看它。 - Chev


你可以将一个javascript块中的部分视图加载到头部的样式中,但考虑到你可能想要头部中的javascript块出于同样的原因,这将是愚蠢的。

我最近发现了一些很酷的东西。您可以将部分视图序列化为字符串,并将其作为JSON对象的一部分发送回客户端。这使您可以传递其他参数以及视图。

将视图作为JSON对象的一部分返回

您可以使用JQuery和ajax获取JSON对象,并使用部分视图加载它,然后另一个JSON属性可能是您的样式块。 JQuery可以检查你是否返回了样式块,如果是,则将其放入head部分。

就像是:

$.ajax(
{
     url: "your/action/method",
     data: { some: data },
     success: function(response)
     {
          $('#partialViewContainer).html(response.partialView);
          if (response.styleBlock != null)
               $('head').append(response.styleBlock);
     }
});

1
2017-11-18 00:15



好的想法,这会起作用,但这取决于用户是否启用了javascript(如果您正在加载脚本资源,这是公平的,但对于CSS来说则不是那么多。) - kristian


你可以用一个 HttpModule 操纵响应HTML并将任何CSS /脚本引用移动到适当的位置。这不是理想的,我不确定性能影响,但它似乎是解决问题的唯一方法,没有(a)基于javascript的解决方案,或(b)反对MVC原则。


1
2017-11-18 23:48





另一种违背MVC原则的方法是使用ViewModel并响应页面的Init事件来设置所需的css / javascript(即myViewModel.Css.Add(“。css”)并在你的头部呈现viewmodel上的css-collection的内容。

为此,您需要创建一个基本的viewmodel类,其他所有模型都继承自ala

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>

0
2017-11-18 12:41



虽然OP没有提到部分的ajax请求,但这当然有效,只作为标准页面请求的一部分。我想挑战是让它适用于部分视图,无论是作为单个请求的一部分还是作为ajax刷新(我无法看到它如何工作,除非它通过javascript注入头部分) - jim tollan
哎呀!我根本不喜欢这个。我更倾向于违反保留样式的协议,而不是抛弃我的MVC应用程序中的关注点! - Chev


以下仅在启用了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的情况下才能为我工作,从而限制了它的实用性。


0
2017-11-18 13:27