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





5.00/5 (1投票)
一种自动注册 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">
项目组织
项目结构必须如下示例所示
在上面的示例中,每个视图都在 ViewScripts 文件夹中拥有其关联的 JavaScript 文件。 请记住,即使是部分视图也可以拥有自己的 JavaScript,即使在父视图中多次呈现该视图,也会引用它一次。