尝试从局部视图向MVC 3 Razor网站的布局文件添加JS和CSS

7

我目前使用的方法如下所示,将以下代码添加到布局文件的头部以添加脚本和CSS文件。

public static class HtmlHelperExtensions
{
    public static MyCompanyHtmlHelpers MyCompany(this HtmlHelper htmlHelper)
    {
        return MyCompanyHtmlHelpers.GetInstance(htmlHelper);
    }    
}

public class MyCompanyHtmlHelpers
{
    private static MyCompanyHtmlHelpers _instance;

    public static MyCompanyHtmlHelpers GetInstance(HtmlHelper htmlHelper)
    {
        if (_instance == null)
            _instance = new MyCompanyHtmlHelpers();

        _instance.SetHtmlHelper(htmlHelper);

        return _instance;
    }

    private HtmlHelper _htmlHelper;

    public ItemRegistrar Styles { get; private set; }
    public ItemRegistrar Scripts { get; private set; }

    public MyCompanyHtmlHelpers()
    {
        Styles = new ItemRegistrar(ItemRegistrarFromatters.StyleFormat);
        Scripts = new ItemRegistrar(ItemRegistrarFromatters.ScriptFormat);
    }

    private void SetHtmlHelper(HtmlHelper htmlHelper)
    {
        _htmlHelper = htmlHelper;
    }
}

public class ItemRegistrar
{
    private readonly string _format;
    private readonly List<string> _items;

    public ItemRegistrar(string format)
    {
        _format = format;
        _items = new List<string>();
    }

    public ItemRegistrar Add(string url)
    {
        if (!_items.Contains(url))
            _items.Insert(0, 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 ItemRegistrarFromatters
{
    public const string StyleFormat = "<link href=\"{0}\" rel=\"stylesheet\" type=\"text/css\" />";
    public const string ScriptFormat = "<script src=\"{0}\" type=\"text/javascript\"></script>";
}

使用Html.MyCompany().Styles.Add("/Dashboard/Content/Dashboard.css");添加文件... 并使用@Html.MyCompany().Styles.Render()在Layout_.cshtml中进行呈现。
我的问题是这是一个静态方法,意味着它会保留样式表和脚本文件的列表。
我需要做的与此相同,但不需要持久保存它。每次请求都需要重新制作列表,因为它们从页面到页面变化,具体页面上的外观也会发生变化。
是否可以在添加所需的脚本之前或呈现后清除每个请求上的列表?
更新: 不使用部分、RenderPartial或RenderaActions的原因是防止同样的样式表或脚本文件被添加到Layout文件中超过一次。
我正在构建的站点有一个Layout_.cshtml,其中包含基本布局。然后,由一个视图使用循环遍历项目列表,并为每个项目调用RenderAction,以输出该项目的特定部分视图。这些部分视图有时需要添加样式表和脚本。
由于可能需要从不同的部分视图添加许多不同的脚本和样式表,因此全局样式和脚本列表是我认为唯一可以完成此操作的方式,因此有一个全局位置来检查脚本是否已添加到集合中,然后按添加顺序一次性呈现它们。
更新2: 真正的问题是如何执行相同类型的函数(全局列表),但不使用静态扩展方法。

那个静态字段注定要失败!不要这样做...看着... - Marc Gravell
1
我不太确定为什么你需要像这样做?你不能用sections、RenderPartial或者RenderActions来实现吗? - Yngve B-Nilsen
是的,静态变量确实很麻烦,我已经从中学到了教训,但我的选择并不多 :) 我仍然认为我需要一个全局列表来维护脚本和样式表,以便能够更好地管理它们。 - Daniel Eldström
在父视图中使用@Url.Content()包含所需的内容不是更容易吗? - Chris S
2个回答

9
我会用章节来完成这个,即:

我会用章节来完成这个,即:

@section head {
    ...add whatever you want here...
}

从布局中呈现“head”部分:
<head>
...other stuff here...
@RenderSection("head", required: false)
</head>

如果您不需要分节,并且不想将其传递,我建议在此处使用HttpContext;针对HttpContext.Current.Items[someKey]存储一些数据。如果为null,则创建一个新的并将其存储在上下文中。
例如:
public static MyCompanyHtmlHelpers GetInstance(HtmlHelper htmlHelper)
{
    const string key = "MyCompanyHtmlHelpersInstance";
    IDictionary items = (htmlHelper == null || htmlHelper.ViewContext == null
        || htmlHelper.ViewContext.HttpContext == null)
        ? HttpContext.Current.Items : htmlHelper.ViewContext.HttpContext.Items;

    MyCompanyHtmlHelpers obj = (MyCompanyHtmlHelpers)items[key];
    if (obj == null)
    {
        items.Add(key, obj = new MyCompanyHtmlHelpers());
    }
    return obj;
}

@Marc:在部分定义前面缺少@。除此之外,点赞 :) - Yngve B-Nilsen
@Daniel - 哦,我明白了;是的,为此你需要将它们收集到列表或其他数据结构中,例如使用HttpContext方法 - 只需放弃那个静态变量 ;p - Marc Gravell
@Daniel的答案已更新以说明;现在它是线程安全的并且每个请求都有效。 - Marc Gravell
@Marc,如果我理解正确的话,我应该修改我的代码将列表存储在HttpContext中。这样理解对吗? - Daniel Eldström
尝试使用 head 方法。似乎是在页面完成后加载了该部分或类似的东西,因为我放在 head 中的 CSS 需要一点时间才能加载。 - Oren A
显示剩余4条评论

0
你需要做的是以稍微不同的方式扩展Html助手。
public static MvcHtmlString AddStyle(this HtmlHelper<TModel> html, string styleUrl)
{
    string styleTag = string.Format("<link rel='stylesheet' type='text/css' href='{0}' />", styleUrl);
    return MvcHtmlString.Create(styleTag);
}

然后在你的视图中只需这样做:

<head>
    @Html.AddStyle("/Dashboard/Content/Dashboard.css")
</head>

如果您需要根相对URL,只需添加Url内容助手即可。
<head>
    @Html.AddStyle(Url.Content("~/Dashboard/Content/Dashboard.css"))
</head>

这个如何从局部视图将样式添加到布局文件中? - Daniel Eldström
我误解了你的问题。 - Chev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接