【问题标题】:How to intercept view rendering to add HTML/JS on all partial views?如何拦截视图渲染以在所有局部视图上添加 HTML/JS?
【发布时间】:2011-12-27 07:30:12
【问题描述】:

我需要从约定驱动的位置(如 ~/ClientApp/Controllers/Home/Home.js,如果加载位于 ~/Views/Home/Home.cshtml 的视图)编写 js 文件的内容。我该怎么做?

示例:如果文件 ~/Views/Home/Home.cshtml 看起来像:

<div id="some-partial-view">
   <!-- ... -->
</div>

文件 ~/ClientApp/Controllers/Home/Home.Controller.js 看起来像

function HomeController() {
  //some code
}

那么网络服务器返回的渲染视图应该看起来像(如果使用 fiddler)

<!--ommitted <html> <body> tags -->

<div id="some-partial-view">
   <!-- ... -->
</div>

<script type="text/javascript">
   function HomeController() {
       //some code
   }
</script>

一种方法是添加一个 HTML Helper 来执行此操作,例如:

<div id="some-partial-view" ng:Controller="HomeController">
   <!-- ... -->
</div>
@Html.IncludeController("HomeController") 

但是,我不想在所有部分视图中重复这一点。

有什么想法吗?

【问题讨论】:

  • 在您的局部视图中引用您的 javascript 文件,
  • 我想跳过这一步,因此问题。想在视图渲染时编织js文件。还想减少往返,因此这不是一个选择。
  • 不清楚你说的“视图渲染时编织js文件”是什么意思?
  • 为了清楚起见已经更新了问题:)

标签: asp.net-mvc razor


【解决方案1】:

您可以编写自定义视图:

public class MyRazorView : RazorView
{
    public MyRazorView(ControllerContext controllerContext, string viewPath, string layoutPath, bool runViewStartPages, IEnumerable<string> viewStartFileExtensions, IViewPageActivator viewPageActivator)
        : base(controllerContext, viewPath, layoutPath, runViewStartPages, viewStartFileExtensions, viewPageActivator)
    {

    }

    protected override void RenderView(ViewContext viewContext, TextWriter writer, object instance)
    {
        base.RenderView(viewContext, writer, instance);

        var view = (BuildManagerCompiledView)viewContext.View;
        var context = viewContext.HttpContext;
        var path = context.Server.MapPath(view.ViewPath);
        var viewName = Path.GetFileNameWithoutExtension(path);
        var controller = viewContext.RouteData.GetRequiredString("controller");
        var js = context.Server.MapPath(
            string.Format(
                "~/ClientApp/Controllers/{0}/{0}.{1}.js",
                viewName,
                controller
            )
        );
        if (File.Exists(js))
        {
            writer.WriteLine(
                string.Format(
                    "<script type=\"text/javascript\">{0}</script>",
                    File.ReadAllText(js)
                )
            );
        }
    }
}

还有一个自定义视图引擎,它会在请求部分视图时返回此自定义视图:

public class MyRazorViewEngine : RazorViewEngine
{
    protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
    {
        return new MyRazorView(
            controllerContext, 
            partialPath, 
            null, 
            false, 
            base.FileExtensions, 
            base.ViewPageActivator
        );
    }
}

将在Application_Start注册:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);

    ViewEngines.Engines.Clear();
    ViewEngines.Engines.Add(new MyRazorViewEngine());
}

您可能需要调整一些路径,因为在您的问题中不太清楚 js 的确切位置,但通常您应该在答案中有足够的详细信息。

【讨论】:

  • 正是我想要的:) 只是认为除了编写自定义视图引擎之外还有另一种方法。非常感谢:)
  • @leypascua,还有其他方法,但这个是最干燥的。
  • @DarinDimitrov 有没有办法可以用其他东西替换 writer 的所有 HTML?另外,只有当它是控制器操作使用的视图时,我如何才能执行此操作,例如我有一个HomeController 和操作Home,并且我希望此代码仅在视图Home 上执行。今天它从页面上使用的所有视图运行。
【解决方案2】:

将所有 javascript 包含在外环中会更有意义,然后通过 index.php 或任何地方包含它...

我个人使用 jQuery,并像这样包含每个对象...

//View Objects
(function($){

var views = {

   init: function()
   {
      this.view1();
      this.view2();
   },
   view1 : function()
   {
     // I am
   },
   view2 : function()
   {
     // all yours
   }

}
//call/invoke my view objects
$(function(){

    //call view object via init()
    view.init();
});

})(jQuery);

【讨论】:

  • 不是一个选项。目标是按需加载 JS,仅在真正需要时才加载。
  • if (getElementbyID(id)){ //load me ie: elements.sexyID(); }
猜你喜欢
  • 2016-02-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多