我正在为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?
答案 0 :(得分:5)
有3个主要案例可以解决您的问题:
因此,在您的示例中,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帮助器。我没有看到任何解决这个问题的好方法,但这里有几个想法。
$(".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" />