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

Referencing same js files from multiple locations using partial views

我正在为 MVC6 应用程序设置架构,并且严重依赖 ViewComponents。我的目标是让每个 ViewComponent 都有自己的 javascript 部分,但是从阅读 here rendersection 不适用于 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。当我使用 chrome f12 调试并观看网络部分时,我没有看到相同的 javascript 文件被多次下载。我仍然对这个解决方案有不好的感觉。我环顾四周,没有找到任何我真正喜欢的处理 js 文件和 ViewComponents 的好的解决方案。像这样的东西可以满足我的需要。

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

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

  1. ViewComponent添加0次,相应的JavaScript库添加0次
  2. ViewComponent添加1次,对应的JavaScript库添加1次,动态创建初始化JavaScript创建一次,放在库之后。
  3. 多次添加ViewComponent,添加1次对应JavaScript库和为每个ViewComponent创建动态创建初始化JavaScript,都放在库之后。

因此,在您的示例中,jquery 和 app.js 是您的库,而动态创建的初始化 JavaScript 是在 <script type="text/javascript"> 标记中引用 @Model 的部分。假设我们将您的组件添加到视图中 3 次(我将从调用您的组件 3 次的视图中将 @RenderBody() 替换为生成的 html):

<!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 次用于视图组件。任何好的浏览器都应该只下载一次文件,但会多次加载到内存中,并且只会多次覆盖相同的全局变量(例如 $)。

您可能还想将库移动到布局的顶部并从视图组件中删除引用 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 scripts {...}
  2. 创建一个库js来初始化这个组件并从元素中设置数据属性

$(".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" />