我希望能够在Javascript中构建一个类似于树的对象层次结构,该层次结构对应于页面上的ASP.NET MVC 3 Razor视图。计划是在Razor视图和定义其逻辑的Javascript文件之间进行一对一的对应(以接受一些初始化参数的构造函数的形式)。简单的例子可能如下所示:
_Layout.cshtml <-> Global.js
SplitterPane.cshtml <-> SplitterPane.js
Grid.cshtml <-> Grid.js
Tree.cshtml <-> Tree.js
我会使用构造函数来构建层次结构,例如
var page = new Global(global_options);
var splitter = new SplitterPane(splitter_options);
var grid = new Grid(grid_options);
var tree = new Tree(tree_options);
page.addChild(splitter);
splitter.addChild(grid);
splitter.addChild(tree);
当然,所有这些代码都应该根据从部分视图收集的元数据在根(布局)视图的上下文中自动构建。视图提供的元数据包含初始化其Javascript对象和要加载的Javascript文件所需的选项。
与WebForms不同,MVC视图没有任何我所知道的自然层次结构,在视图及其部分(子)视图之间传递信息似乎相当棘手。如果在视图中使用Html.Action
之类的帮助程序,则“子视图”的整个处理将独立进行,因此它们甚至不共享Page
对象。我需要的是某种中心位置,其中视图可以在呈现时存储元数据,以便可以在布局视图中使用它来组合和输出完整的脚本。
我能想到的一种方法是使用HttpContext.Current.Items
临时存储一组视图元数据对象。所有视图都将元数据存放在那里,布局视图将使用它。执行的顺序似乎符合我的期望,但是我仍然无法重建视图的树层次结构。为了能够做到这一点,我需要使用一个堆栈,其中视图将在其渲染开始时注册并在结束时取消注册,以便可以在顶部找到父级。
答案 0 :(得分:2)
您可以编写自定义视图引擎:
public class MyViewEngine : RazorViewEngine
{
private class MyRazorView : RazorView
{
public MyRazorView(ControllerContext controllerContext, string viewPath, string layoutPath, bool runViewStartPages, IEnumerable<string> viewStartFileExtensions, IViewPageActivator viewPageActivator)
: base(controllerContext, viewPath, layoutPath, runViewStartPages, viewStartFileExtensions)
{
}
protected override void RenderView(ViewContext viewContext, System.IO.TextWriter writer, object instance)
{
var stack = viewContext.HttpContext.Items["stack"] as Stack<string>;
if (stack == null)
{
stack = new Stack<string>();
viewContext.HttpContext.Items["stack"] = stack;
}
// depending on the required logic you could
// use a stack of some model and push some additional
// information about the view (see below)
stack.Push(this.ViewPath);
base.RenderView(viewContext, writer, instance);
}
}
protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
{
return new MyRazorView(controllerContext, viewPath, masterPath, true, base.FileExtensions, base.ViewPageActivator);
}
protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
{
return new MyRazorView(controllerContext, partialPath, null, false, base.FileExtensions, base.ViewPageActivator);
}
}
您将在Application_Start
注册:
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new MyViewEngine());
现在您可以编写一个自定义HTML帮助程序,它将选择存储在HttpContext中的堆栈并执行一些有用的操作:
public static class HtmlExtensions
{
public static IHtmlString BuildTree(this HtmlHelper htmlHelper)
{
var stack = htmlHelper.ViewContext.HttpContext.Items["stack"] as Stack<string>;
if (stack == null)
{
return MvcHtmlString.Empty;
}
// TODO: your custom logic to build the tree
...
}
}
并在你的_Layout结束时:
...
<script type="text/javascript">
@Html.BuildTree()
</script>
</body>
答案 1 :(得分:-2)
如果您只想将视图与Javascript文件关联,请在layout.cshtml中定义一个部分(在正文标记结束之前):
@RenderSection("scripts", false")
然后在您的页面和视图中:
@section scripts {
<script type="text/javascript" src="path to script"></script> }
但是,一旦您进入部分视图,这将无效。为了处理部分视图,我使用了自定义Html扩展。 @ Html.RenderResource(“{sectionname},”〜/ {资源路径}“)