使用部分视图从多个位置引用相同的 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 个主要案例可以理想地解决您的问题:
- ViewComponent添加0次,相应的JavaScript库添加0次
- ViewComponent添加1次,对应的JavaScript库添加1次,动态创建初始化JavaScript创建一次,放在库之后。
- 多次添加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 助手。我还没有看到任何解决这个问题的好方法,但这里有一些想法。
- 在视图中,在调用组件 (Component.InvokeAsync("MyComponent")) 后,立即将 javascript 添加到 @section scripts {...}
- 创建一个库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" />
我正在为 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 个主要案例可以理想地解决您的问题:
- ViewComponent添加0次,相应的JavaScript库添加0次
- ViewComponent添加1次,对应的JavaScript库添加1次,动态创建初始化JavaScript创建一次,放在库之后。
- 多次添加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 助手。我还没有看到任何解决这个问题的好方法,但这里有一些想法。
- 在视图中,在调用组件 (Component.InvokeAsync("MyComponent")) 后,立即将 javascript 添加到 @section scripts {...}
- 创建一个库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" />