是否可以将JavaScript放在部分视图中


68

我正在使用Web应用程序,其中主页包含两个部分:始终可见的常量块和由3个局部视图之一组成的信息块。每个部分视图都是AJAX请求的结果,并且仅被加载一次(由jquery提供切换窗口之后)。它运作良好,但我遇到了一个问题。

部分视图的html代码包含在常量块和信息块中使用的js函数。加载页面后,这些函数可以互相“看到”并且可以工作,但是resharper找不到函数声明并就此警告我。由于无法在其代码中找到剃刀语法,因此无法通过将它们传输到外部js文件来解决问题。

我该怎么办?

谢谢。

更新:

最后,我决定解决将我的js代码与视图分离的问题。因此,新的问题是如何将razor语法包含在js文件中,或者可以接受的替代方法是什么。我发现的流行解决方案是使用全局变量,数据属性以及我更喜欢的解决方案-John Katsiotis的RazorJS库。

http://djsolid.net/blog/razorjs---write-razor-inside-your-javascript-files

我希望它能稳定工作并使Resharper开心。

干杯!

更新:

3年后,我想起了这个问题,并决定根据我的经验对其进行更新。实际上,我现在不建议为此使用其他库。尤其是如果您不是项目团队中的唯一成员…最好在所有库中确保它们得到创建者和社区的支持,并且可以轻松集成到您的IDE中(例如,使用特殊语法) 。此外,您团队中的所有人员都应该知道它是如何工作的。所以现在我建议做以下事情:

  1. 将所有JS放在单独的文件中。尽可能地隔离它。为此提供外部API。
  2. 从您的视图中调用API函数。
  3. 将所有Razor生成的URL,文本消息,常量作为资源参数传递。

例如:

js文件:

$.api.someInitFunction = function(resources){ ... }

视图:

<script>
    $.api.someInitFunction({
        urls: { myAction: '@Url.Action("MyAction", "MyController")' },
        messages: { error: '@errorMessage' },
        consts: { myConst: @myIntConst }
    });
</script>

我无法确定哪个答案对我更有用:)
Tomy 2012年

感谢并欢迎您到Stackoverflow :)
Wahid Bitar 2012年

如此愉快的接待开始令人愉快,非常感谢!
Tomy 2012年

看看这个; 在不影响效率的情况下将脚本置于局部视图中的一种很好的解决方案
Mojtaba

1
@ Worthy7如果使用相同的技术,则实际上是
Tomy

Answers:


38

如果Resharper警告您,那没什么大不了的^ _ ^

但是如果我是你,我根本不会在部分视图中使用JavaScript

由于部分视图可以多次插入一页中,因此您的JavaScript会遇到问题。

对于您的情况,如果您无法将JavaScript与JS文件分开,则只需创建另一个PartialView并将这些脚本放入其中,然后将其呈现在主页中即可。


谢谢,瓦希德!但是有时候Resharper的代码确实比我做的更好:)实际上,我知道将js放入部分视图不是一个好主意。但是正如我所说,在我的页面上它们以一个副本存在,因此嵌套只是“ impossibru”。根据您对脚本局部视图的建议,我将使主视图变得非常好。但是,遗憾的是RenderPartial无法解决Resharper问题。我能说错吗?
Tomy 2012年

3
如果这是一个很小的应用程序,并且您不想花更多的时间在它上面,那么就保持您的工作不变。但是,如果您在谈论“编程习惯”,则应将JavaScript与View分开。
瓦希德·比塔尔

并且对于@Html.ActionLink(...)有很多解决方案,但其中不包括将JavaScript直接放入PartialView中。您可以看看这个答案stackoverflow.com/a/3789959/105445
Wahid Bitar,2012年

10

如果您想编写封装了“小部件”的部分视图,只要将它们包含在页面中就可以使用,那么将脚本块嵌入部分视图中是将标记和初始化脚本包装在部分视图中的一种干净方法。例如,我可能有一个名为“ _EventList”的局部视图,该视图在整个站点中都使用。如果我将其放置在母版页的两个位置上,则应该可以正常工作,而且我不希望在母版页中编写逻辑来初始化小部件。

如果您永远不会在页面中多次使用它,那么它很简单。但是,如果可以的话,请包装脚本,这样它就不会执行两次。见下文。为了实现Stack Overflow片段,我通过在代码片段中重复两次局部视图来模拟它,以表示在母版页中两次包含局部视图。

我的母版页可能看起来像:

<div id="left-nav">
   @Html.Partial("_EventList")           
</div>

<div id="body">
</div>

<div id="right-nav">
   @Html.Partial("_EventList")
</div>

例:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<!-- Self-contained partial view containing widget -->

<div id="widgetDiv" class="panel panel-default">

    <div class="panel-heading">Event Dates</div>
    <div class="panel panel-group">
       <ul class="widget">
         <!-- These will load dynamically -->
       </ul>
    </div>

    <script>
        $(document).ready(function() {

            // Run this once only in case widget is on page more than once
            if(typeof $widget == 'undefined') {
                $widget = $("ul.widget"); // could be more than one
                // mock data to simulate an ajax call
                var data = [
                   {Description: "March", StartDate: "03/01/2015"},
                   {Description: "April", StartDate: "04/01/2015"},
                   {Description: "May", StartDate: "05/01/2015"}
                ];

                $.each($widget, function(w, widget) {
                    // might be an $.ajax call
                    $.each(data, function(i, row) {
                        $(widget).append("<li><a href='/Widget/Search?startDate=" + row.StartDate + "'>" + row.Description + "</a></li>");
                    });
                });
            }
        });
    </script>
</div>
<!-- End of widget / partial view -->



<!-- Second copy of above for sake of example snippet -->
<!-- No need to read further -->









<!-- Self-contained partial view containing widget -->

<div id="widgetDiv" class="panel panel-default">

    <div class="panel-heading">Event Dates</div>
    <div class="panel panel-group">
       <ul class="tinylist nav nav-sidebar widget">
         <!-- These will load dynamically -->
       </ul>
    </div>

    <script>
        $(document).ready(function() {

            // Run this once only in case widget is on page more than once
            if(typeof $widget == 'undefined') {
                $widget = $("ul.widget"); // could be more than one
                // mock data to simulate an ajax call
                var data = [
                   {Description: "March", StartDate: "03/01/2015"},
                   {Description: "April", StartDate: "04/01/2015"},
                   {Description: "May", StartDate: "05/01/2015"}
                ];

                $.each($widget, function(w, widget) {
                    // might be an $.ajax call
                    $.each(data, function(i, row) {
                        $(widget).append("<li><a href='/Widget/Search?startDate=" + row.StartDate + "'>" + row.Description + "</a></li>");
                    });
                });
            }
        });
    </script>
</div>
<!-- End of widget / partial view -->


1
尽管事实上有更多被赞成的答案,但我还是建议您使用此方法,而不是仅仅为了将它们按扩展名分组而拆分高度一致的依赖项。所以是我的一大笔钱。
Cristian E.

我非常同意:不要将内聚的HTML和JS分开。毫无疑问...但是您的示例局部视图不适用于ASP MVC的Visual Studios模板的所有使用者:在内部_Layout.cshtmljQuery渲染之后, @RenderBody()因此您无法使用它。您的解决方法并不是真的更好:第一行将<script src=".../jquery.min.js"></script>包含jQuery两次或更多次(每个局部视图1x,您内部1x _Layout.cshtml
Marcel

@Marcel-该示例旨在在代码段编辑器中运行以展示该技术。我实际上警告过我的答案和建议的改进,包括多个jquery,所以我不确定您是否阅读了我的“免责声明”。我实际的布局页面通常在头部包含jquery和其他脚本。额外的工作超出了我当时的回答范围/时间要求。欢迎您改进此答案,只要它仍在Stack Overflow中
起作用即可-codenheim

如果您包含在局部视图中的脚本不依赖于其他脚本(例如jquery),那么这种方法也是不错的选择,此外,如果您使用head调用头部分中的脚本,defer则会在局部视图中出现错误,并且必须再次加载jquery ...
Offir Pe'er

4

我同意Wahid的观点,即不应将JavaScript完全或部分地置于视图中。我已经看到了足够的代码来执行此操作,以了解它只会导致不良后果。

我还要说的是,您应该能够将Razor语法中封装的逻辑传输到JavaScript中,只需将逻辑所需的信息传递给JavaScript。

我只是从经验中猜测下一条注释,但是您应该以与设计C#或VB.NET代码的结构相同的方式来设计JavaScript。这样,您使用Razor的逻辑应该成为JavaScript的一部分。

这样,您的JavaScript将更易于维护,我认为Resharper也应该更快乐。


感谢您的回答!但是问题不在于逻辑。我使用Razor构建链接(例如,Url.Action)和类似的东西。我猜将它们作为参数传递看起来很奇怪。
Tomy 2012年

对于链接,您仍然可以将它们放在href上,只需使用preventDefault。html5数据属性在这些情况下也很有用。查看dojo或yui3,看看如何构建库。
eaglestorm 2012年

@eaglestorm,我唯一的问题是我尚未得到答案。创建@section调用的目的是可以将特定于视图的呈现输出放置在视图的那些区域中。如果我有一个企业级应用程序并且有数百个脚本,那么我不想将它们全部包含在我的布局中,因为那样会使我的html呈现的输出变得巨大。允许的包含@section在视图和/或部分观点是在我与性能有关的意见是必须的。
clockwiseq

@Keith我建议您在这种情况下合并并缩小JavaScript。然后,浏览器将加载一次并对其进行缓存。这确实意味着您必须编写JavaScript,以便它可以处理此问题。
eaglestorm

感谢您的回复@eaglestorm。我会试一下。
clockwiseq

2

我这样做,发现它非常方便。它可以很好地动态加载具有ViewBag,HttpContext等功能的部分javascript代码段。

结果是感觉就像使用T4模板。

如果添加像这样的幻影脚本标签,您甚至可以获取javascript验证,智能感知等。

@using System.Configuration
@if (false)
{
    @:<script type="text/javascript">
}    
        $scope.clickCartItem = function(cartItem) {
            console.log(cartItem);
            window.location.href =@Html.Raw("('" + ConfigurationManager.AppSettings["baseUrl"] + "/Checkout/' + cartItem.ItemId)");
        };
        dataAccess.getCart(
        function (response) {
            //...
        },
        function (response) {
            //...
        }
        );

@if (false)
{
    @:</script>
}

0

对于以后这个问题的观众,这是我的经验。我认为将仅供部分使用的脚本保留在用于组织的部分中是一个好主意。

我在调试过程中遇到的问题,有时我很难碰到断点,除非将脚本移至父视图,否则无法解决问题。最有可能是由于多次打印功能。我希望各节可以更好地解决和组织这个问题,但是部分视图不支持各节(至少在MVC 4中不支持)。

因此,我的答案是出于维护和调试的目的,不应将任何脚本放入局部视图中。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.