将 JavaScript 放在部分视图中可以吗

IT技术 javascript asp.net-mvc razor partial-views
2021-03-01 03:40:03

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

局部视图的 html 代码包含在常量块和信息块中使用的 js 函数。当页面加载时,这些函数可以“看到”彼此并且可以工作,但是 resharper 找不到函数声明并警告我这一点。由于可以在他们的代码中找到 razor 语法,我无法通过将它们传输到外部 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>
5个回答

如果 Resharper 警告你这没什么大不了的^_^

但如果我是你,我根本不会把 JavaScript 放在局部视图中

因为部分视图可以在一个页面中多次插入,所以您的 JavaScript 会出现问题。

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

谢谢,瓦希德!但有时 Resharper 代码确实比我做得好 :) 事实上,我知道将 js 放入部分视图并不是一个好主意。但正如我所说,在我的页面上,它们存在于一个副本中,因此例如嵌套只是“不可能的”。按照您关于使用脚本的局部视图的建议,我将使主视图变得非常好。不过可惜的是RenderPartial并没有解决Resharper的问题。我会错吗?
2021-04-23 03:40:03
如果这是一个小应用程序并且您不想在它上面花费更多时间,那么就保持您的工作不变。但是,如果您谈论的是“编程习惯”,那么您应该将 JavaScript 与视图分开。
2021-04-24 03:40:03
对于@Html.ActionLink(...)有很多解决方案,但没有一个是将 JavaScript 直接放在 PartialView 中。你可以看看这个答案stackoverflow.com/a/3789959/105445
2021-05-14 03:40:03

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

如果您永远不会在一个页面中多次使用它,这很简单。但是,如果可以,请包装脚本,使其不会执行两次。见下文。为了堆栈溢出片段,我通过在代码片段中重复局部视图两次来模拟它,以表示在母版页中包含局部视图两次。

我的母版页可能如下所示:

<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 -->

如果您在部分视图中包含的脚本不依赖于其他脚本(如 jquery),则此方法很好,此外,如果您在 head 部分中使用调用脚本,defer您将在部分视图中出现错误,并且必须再次加载 jquery ...
2021-04-25 03:40:03
@Marcel - 该示例旨在在代码片段编辑器中运行以展示该技术。我实际上警告过这一点,包括多个 jquery 包含,在我的回答和建议的改进中,所以我不确定你是否阅读了我的“免责声明”。我真正的布局页面通常在 head 部分有 jquery 和其他脚本。额外的工作超出了我当时回答的范围/时间要求。欢迎您改进此答案,只要它在 Stack Overflow 中仍然有效
2021-05-01 03:40:03
尽管有更多赞成的答案,但我绝对推荐这种方法,而不是为了按扩展对它们进行分组而拆分高度内聚的依赖项。所以是的,我给了一个很大的++。
2021-05-03 03:40:03
我强烈同意:不要将内聚的 HTML 和 JS 分开。毫无疑问......但是您的示例部分视图不适用于 ASP MVC 的 Visual Studios 模板的所有消费者:内部_Layout.cshtmljQuery 是在之后 呈现的@RenderBody()因此您无法使用它。您的解决方法并不是更好:第一行将<script src=".../jquery.min.js"></script>包含 jQuery 两次或更频繁(每个局部视图 1x 和您中的 1x _Layout.cshtml
2021-05-15 03:40:03

我同意 Wahid 的观点,你不应该将 JavaScript 放在视图中,无论是部分还是其他。我已经看到了足够多的代码来做到这一点,我知道它只会带来不好的结果。

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

我只是根据下一条评论的经验进行猜测,但您应该像设计 C# 或 VB.NET 代码的结构一样设计 JavaScript。这样你使用 Razor 的逻辑应该是你的 JavaScript 的一部分。

这样你的 JavaScript 会更容易维护,我认为 Resharper 也应该更快乐。

感谢您的回答!但问题不在于逻辑。我使用 Razor 来构建链接(例如 Url.Action)和类似的东西。我猜将它们作为参数传递看起来很奇怪。
2021-04-21 03:40:03
对于链接,您仍然可以将它们放在 href 上,只需使用 preventDefault。在这些情况下,html5 数据属性也很有用。查看 dojo 或 yui3 并查看库是如何构建的。
2021-05-01 03:40:03
@Keith 在这种情况下,我建议您连接并缩小您的 javascript。然后浏览器将加载一次并缓存它。这确实意味着您必须编写 javascript 以便它可以处理这个问题。
2021-05-05 03:40:03
@eaglestorm,我对你的回答唯一的问题是我还没有得到答案。创建@section调用的目的将特定于视图的渲染输出放置在视图的这些区域中。如果我有一个企业级应用程序并且有数百个脚本,我不想将它们全部包含在我的布局中,因为这会使我的 html 的渲染输出变得巨大。@section在我看来,在性能方面,必须允许在视图和/或部分视图中包含 a。
2021-05-06 03:40:03
感谢@eaglestorm 的回复。我会试一试。
2021-05-17 03:40:03

我这样做并发现它非常方便。在 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>
}

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

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

所以我的回答是为了维护和调试,不应该在局部视图中放置任何脚本。