65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 Razor 引擎的 ASP.NET MVC3 JavaScript 组织

2011年3月23日

CPOL

2分钟阅读

viewsIcon

44708

一种自动注册 JavaScript 视图文件的技术。

引言

ASP.NET MVC 的一个优点是控制器和视图如何通过方法名称、文件名和目录结构自动关联。一些视图可能有一些相关的 JavaScript 代码,这些代码可以分离到文件中(js),我想知道是否有某种模式来组织这些 JavaScript 代码,并使其自动包含在每个对应的视图中。

经过一些研究,我找到了 这篇文章,作者是 Shayne P Boyer,但我的项目使用的是 ASP.NET MVC 3 和 Razor 视图引擎。

此外,我担心的是部分视图,它们可能有自己相关的 JavaScript 文件,并且正在考虑一种方法,以便即使在同一页面上多次使用相同的部分视图,这些脚本也只包含一次。

在这里,我展示了一个 ViewPageBase,它会自动引用当前视图和内部部分视图的 JavaScript 文件(使用 Shayne 建议的结构,并避免重复注册相同的文件)。

ViewPageBase

ViewPageBase 继承自 System.Web.Mvc.WebViewPage<TModel>,并重写了 InitializePage 方法,该方法将搜索相关的 JavaScript 文件。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.WebPages;
using System.Text;
using System.IO;

namespace JSOrganization
{
    public abstract class ViewPageBase<T> : WebViewPage<T>
    {
        protected override void InitializePage()
        {
            base.InitializePage();
           
            AddScriptForView(this.VirtualPath);
        }

AddScriptForView 方法将检查视图是否存在 JavaScript 文件,如果存在,则保留引用。

void AddScriptForView(string path)
{
    if (string.IsNullOrEmpty(path)) { return; }

    var dctScripts = GetScriptsDictionary();
    if (!dctScripts.ContainsKey(path))
    {
        //Change path to the javascripts folder
        path = path.Replace("~/Views/", "~/ViewScripts/");
        //Change the extension to .js
        path = Path.ChangeExtension(path, "js");

        //Check if the file exists
        if (File.Exists(Server.MapPath(path)))
        {
            //Build the javascript reference and keep it in the dictionary
            var tagBuilder = new TagBuilder("script");
            tagBuilder.Attributes.Add("type", "text/javascript");
            tagBuilder.Attributes.Add("src", Url.Content(path));
            dctScripts[path] = string.Format("{0}{1}", 
              tagBuilder.ToString(TagRenderMode.Normal), System.Environment.NewLine);
        }
    }
}

GetScriptsDictionary 将在当前的 HttpContext 中搜索一个字典,该字典保存 JavaScript 文件引用。 此时,程序识别处理的第一个视图,通常是由当前 Action 返回的视图,稍后将在最终 HTML 中包含所有脚本引用。

bool isPrincipalView = false;
const string _viewScriptsKey = "__ViewScripts";
private Dictionary<string, string> GetScriptsDictionary()
{
    var ctx = Context;
    var dctScripts = default(Dictionary<string, string>);
    if (!ctx.Items.Contains(_viewScriptsKey))
    {
        //If the dictionary is not created yet, then this view is the principal
        isPrincipalView = true;
        dctScripts = new Dictionary<string, string>();
        ctx.Items[_viewScriptsKey] = dctScripts;

    }
    else
    {
        dctScripts = ctx.Items[_viewScriptsKey] as Dictionary<string, string>;
    }
    return dctScripts;
}

然后,重写了 ExecutePageHierarchy。 这是“主视图”在 HTML 顶部插入所有 JavaScript 引用的地方。

    public override void ExecutePageHierarchy()
    {
        base.ExecutePageHierarchy();

        //This code will execute only for the principal view,
        //not for the layout view, start view, or partial views.
        if (isPrincipalView)
        {
            var dctScripts = GetScriptsDictionary();
            var sw = this.Output as StringWriter;
            var sb = sw.GetStringBuilder();

            //add here the javascript files for layout and viewstart
            AddScriptForView(this.Layout);
            AddScriptForView("~/Views/_ViewStart.cshtml");

            //Insert the scripts
            foreach (var pair in dctScripts)
            {
                sb.Insert(0, pair.Value);
            }
        }
    }
}

public abstract class ViewPageBase : ViewPageBase<dynamic> { }

使用基础视图类

要使其工作,所有视图都必须继承自 ViewPageBase。 有两种方法可以实现这一点。

一种方法是逐个视图继承,在每个视图的顶部插入以下语句

@inherits JSOrganization.ViewPageBase  

另一种方法是在 Views/Web.config 中指定所有视图的基础类

<system.web.webPages.razor>
    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, 
            Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <pages pageBaseType="JSOrganization.ViewPageBase"> 

项目组织

项目结构必须如下示例所示

organization.PNG

在上面的示例中,每个视图都在 ViewScripts 文件夹中拥有其关联的 JavaScript 文件。 请记住,即使是部分视图也可以拥有自己的 JavaScript,即使在父视图中多次呈现该视图,也会引用它一次。

© . All rights reserved.