如何拦截视图呈现,以便在所有部分视图上添加HTML/JS ?

时间:2023-01-19 16:11:52

I need to write the contents of a js file from a convention-driven location (like ~/ClientApp/Controllers/Home/Home.js if loading the view located at ~/Views/Home/Home.cshtml). How do I do this?

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

Example: if the file ~/Views/Home/Home.cshtml looks like:

例子:如果文件~/视图/Home/Home。cshtml看起来像:

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

And the file ~/ClientApp/Controllers/Home/Home.Controller.js looks like

和文件~ / ClientApp /控制器/ Home / Home.Controller。js的样子

function HomeController() {
  //some code
}

Then the rendered view returned by the webserver should look like (if using fiddler)

然后webserver返回的呈现视图应该是这样的(如果使用fiddler)

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

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

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

One way is to add an HTML Helper that will do this such as:

一种方法是添加一个HTML帮助器,它可以这样做:

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

However, i don't want to repeat this in all partial views.

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

Any ideas?

什么好主意吗?

2 个解决方案

#1


15  

You could write a custom view:

您可以编写自定义视图:

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)
                )
            );
        }
    }
}

and a custom view engine which will return this custom view when a partial view is to be requested:

以及自定义视图引擎,当需要部分视图时,该引擎将返回该自定义视图:

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

which would be registered in Application_Start:

将在Application_Start中注册:

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

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

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

You probably might need to adjust some of the paths as it was not quite clear in your question where exactly should the js be located but normally you should have enough details in the answer.

您可能需要调整一些路径,因为在您的问题中,究竟应该在哪里设置js,但是通常您应该在答案中有足够的细节。

#2


0  

it would make more sense to include all you javascript in the outter ring, then include that via index.php or wherever...

在outter环中包含所有javascript,然后通过索引包含它,这样做更有意义。php或无论…

Personally I use jQuery and I include each object like so...

就我个人而言,我使用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);

#1


15  

You could write a custom view:

您可以编写自定义视图:

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)
                )
            );
        }
    }
}

and a custom view engine which will return this custom view when a partial view is to be requested:

以及自定义视图引擎,当需要部分视图时,该引擎将返回该自定义视图:

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

which would be registered in Application_Start:

将在Application_Start中注册:

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

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

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

You probably might need to adjust some of the paths as it was not quite clear in your question where exactly should the js be located but normally you should have enough details in the answer.

您可能需要调整一些路径,因为在您的问题中,究竟应该在哪里设置js,但是通常您应该在答案中有足够的细节。

#2


0  

it would make more sense to include all you javascript in the outter ring, then include that via index.php or wherever...

在outter环中包含所有javascript,然后通过索引包含它,这样做更有意义。php或无论…

Personally I use jQuery and I include each object like so...

就我个人而言,我使用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);