使用部分视图从多个位置引用相同的js文件

时间:2017-03-31 06:23:37

标签: javascript razor asp.net-core asp.net-core-viewcomponent

我正在为MVC6应用程序设置架构,而且我非常依赖ViewComponents。我的目标是让每个ViewComponent都有自己的javascript部分,但是通过阅读here,渲染不适用于ViewComponents,所以我一直试图以另一种方式进行。

在我的 _Layout.cshtml

我在关闭body标签之前就已经有了这个部分:

  @{Html.RenderPartial("_LayoutScriptsPartial"); }

_LayoutScriptsPartial

<environment names="Development">
  <script src="~/lib/jquery/dist/jquery.js"></script>    
  <script src="~/js/app.js" asp-append-version="true"></script>
</environment>
<environment names="Staging,Production">
      <script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.0.min.js"
        asp-fallback-src="~/lib/jquery/dist/jquery.min.js">
      </script>

       <script src="~/js/app.min.js" asp-append-version="true"></script>
</environment>

现在在/ Views / Shared / Components / MyComponent / Default.cshtml 中的一个组件中,我引用另一个包含此内容的局部视图,它是用于轮播的ViewComponent

 @model MyProj.MyViewModel
 @{Html.RenderPartial("_LayoutScriptsPartial"); }

 @if (!string.IsNullOrEmpty(Model.ImageUrl))
 {


<script type="text/javascript">

    var cssClass= "@Model.cssClass";
    var imageUrl = "@Model.ImageUrl";

    webbCore.carouselSetBackgroundImage(cssClass, imageUrl);

</script>

 }

我必须这样做的唯一原因是我的视图组件可以使用所有必需的js文件。 如您所见,我多次引用_LayoutScriptsPartial。当我使用chromes f12调试并观看网络部分时,我没有多次下载相同的javascript文件。我仍然对这个解决方案感觉不好。我环顾四周,没有找到任何好的解决方案来处理我真正喜欢的js文件和ViewComponents。这样的事情符合我的需要。

我的问题这个解决方案有多好,有什么优点和缺点,有没有更好的方法来处理js文件和ViewComponents?

1 个答案:

答案 0 :(得分:5)

有3个主要案例可以解决您的问题:

  1. ViewComponent添加0次,相应的JavaScript库添加0次
  2. ViewComponent被添加1次,相应的JavaScript库被添加1次,动态创建的初始化JavaScript被创建一次并放在库之后。
  3. 多次添加ViewComponent,添加相应的JavaScript库一次,为每个ViewComponent创建动态创建的初始化JavaScript,并将其全部放在库之后。
  4. 因此,在您的示例中,jquery和app.js是您的库,而动态创建的初始化JavaScript是引用<script type="text/javascript">标记中的@Model的部分。假设我们将您的组件添加到视图中3次(我将使用从调用组件3次的视图中生成的html替换@RenderBody()):

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - MyProj.Web</title>
    
    <environment names="Development,Staging,Production">
        <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
        <link rel="stylesheet" href="~/lib/font-awesome/css/font-awesome.css" />
        <link rel="stylesheet" href="~/css/site.css" />
        <link rel="stylesheet" href="~/css/culture-flags.css" />
    </environment>
    </head>
    <body>
    <header>@Html.Partial("~/Views/Shared/_Header.cshtml")</header>
    <main>
        <nav></nav>
        <article>
            <div class="container body-content">
                <!--@RenderBody()-->
                    <!--@await Component.InvokeAsync("MyComponent", new MyViewModel {cssClass="t1", ImageUrl="1.jpg"})-->
                    <script src="~/lib/jquery/dist/jquery.js"></script>    
                    <script src="~/js/app.js" asp-append-version="true"></script>
                    <script type="text/javascript">
                        var cssClass= "t1";
                        var imageUrl = "1.jpg";
                        webbCore.carouselSetBackgroundImage(cssClass, imageUrl);
                    </script>
                    <!--@await Component.InvokeAsync("MyComponent", new MyViewModel {cssClass="t2", ImageUrl="2.jpg"}) -->
                    <script src="~/lib/jquery/dist/jquery.js"></script>    
                    <script src="~/js/app.js" asp-append-version="true"></script>
                    <script type="text/javascript">
                        var cssClass= "t2";
                        var imageUrl = "2.jpg";
                        webbCore.carouselSetBackgroundImage(cssClass, imageUrl);
                    </script>
                    <!--@await Component.InvokeAsync("MyComponent", new MyViewModel {cssClass="t3", ImageUrl="3.jpg"}) -->
                    <script src="~/lib/jquery/dist/jquery.js"></script>    
                    <script src="~/js/app.js" asp-append-version="true"></script>
                    <script type="text/javascript">
                        var cssClass= "t3";
                        var imageUrl = "t3.jpg";
                        webbCore.carouselSetBackgroundImage(cssClass, imageUrl);
                    </script>
            </div>
        </article>
        <aside></aside>
    </main>
    <footer>@Html.Partial("~/Views/Shared/_Footer.cshtml")</footer>
    <!-- These are the libraries that should only be loaded once -->
    <environment names="Development,Staging,Production">
        <script src="~/lib/jquery/dist/jquery.js"></script>
        <script src="~/js/site.js" asp-append-version="true"></script>
    </environment>
    <!-- Ideally this is where the dynamically create scripts would go -->
    @RenderSection("scripts", required: false)
    </body>
    </html>
    

    正如您所看到的,您将加载jquery库4次,一次用于布局,3次用于ViewComponents。任何好的浏览器都应该只下载一次文件,但会多次加载到内存中,并且会多次覆盖相同的全局变量(例如$)。

    您可能还想尝试将库移动到布局的顶部,并从视图组件中删除引用but that is not a best practice either.

    The main issue is that section doesn't work with ViewComponents and that appears to be by design.您应该将ViewComponent视为花哨的html帮助器。我没有看到任何解决这个问题的好方法,但这里有几个想法。

    1. 在视图中,在您调用组件后立即(Component.InvokeAsync(“MyComponent”)),将您的javascript添加到@section脚本{...}
    2. 创建一个库js,用于初始化此组件并从元素
    3. 设置数据属性

      $(".carousel").each(function() { var css = $(this).data("carousel-css"); var image = $(this).data("carousel-image"); });

      <input class="carousel" type=hidden data-carousel-css="@Model.cssClass" data-carousel-image="@Model.imageURL" />