视图组件中的Javascript
我有一个视图组件,它在Razor(.cshtml)文件中包含一些jQuery。脚本本身非常特定于视图(处理一些第三方库的配置),因此为了组织起见,我希望将脚本和HTML保存在同一个文件中 问题在于_布局脚本部分中没有呈现脚本。显然,这只是有关视图组件的脚本 我可以通过将脚本放在Razor文件中来解决这个问题,但是不能放在脚本部分中 但随后我遇到了依赖性问题——因为jQuery是在对库的引用之前使用的(对库的引用位于_布局文件的底部附近) 除了将对jQuery的引用作为Razor代码的一部分(这会妨碍组件所在位置的HTML呈现)之外,还有其他聪明的解决方案吗 我目前不在代码前面,但如果有人需要查看代码以更好地理解它,我当然可以在有机会时提供它 节仅在视图中工作不在局部视图或视图中工作 组件(视图组件中的Javascript,javascript,c#,asp.net-mvc,razor,asp.net-core-mvc,Javascript,C#,Asp.net Mvc,Razor,Asp.net Core Mvc,我有一个视图组件,它在Razor(.cshtml)文件中包含一些jQuery。脚本本身非常特定于视图(处理一些第三方库的配置),因此为了组织起见,我希望将脚本和HTML保存在同一个文件中 问题在于_布局脚本部分中没有呈现脚本。显然,这只是有关视图组件的脚本 我可以通过将脚本放在Razor文件中来解决这个问题,但是不能放在脚本部分中 但随后我遇到了依赖性问题——因为jQuery是在对库的引用之前使用的(对库的引用位于_布局文件的底部附近) 除了将对jQuery的引用作为Razor代码的一部分(这会
Default.cshtml
独立于主ViewResult
执行,默认情况下其Layout
值为null
),这是通过设计实现的
您可以使用它为局部视图
或视图组件的
视图声明的布局
渲染节。但是,在partials和view组件中定义的节不会流回到渲染视图或其布局。
如果您想在局部视图或视图组件中使用jQuery或其他库引用,则可以在布局
页面中将库拉入标题
,而不是正文
示例:
查看组件:
public class ContactViewComponent : ViewComponent
{
public IViewComponentResult Invoke()
{
return View();
}
}
/Views/[CurrentController]/Components/[NameOfComponent]/Default.cshtml
/Views/Shared/Components/[NameOfComponent]/Default.cshtml
@model ViewComponentTest.ViewModels.Contact.ContactViewModel
<form method="post" asp-action="contact" asp-controller="home">
<fieldset>
<legend>Contact</legend>
Email: <input asp-for="Email" /><br />
Name: <input asp-for="Name" /><br />
Message: <textarea asp-for="Message"></textarea><br />
<input type="submit" value="Submit" class="btn btn-default" />
</fieldset>
</form>
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
..................
@{Html.RenderPartial("YourPartialView");}
..................
@await Component.InvokeAsync("Contact")
..................
@section Scripts {
<script>
//Do somthing
</script>
}
视图组件的位置:
public class ContactViewComponent : ViewComponent
{
public IViewComponentResult Invoke()
{
return View();
}
}
/Views/[CurrentController]/Components/[NameOfComponent]/Default.cshtml
/Views/Shared/Components/[NameOfComponent]/Default.cshtml
@model ViewComponentTest.ViewModels.Contact.ContactViewModel
<form method="post" asp-action="contact" asp-controller="home">
<fieldset>
<legend>Contact</legend>
Email: <input asp-for="Email" /><br />
Name: <input asp-for="Name" /><br />
Message: <textarea asp-for="Message"></textarea><br />
<input type="submit" value="Submit" class="btn btn-default" />
</fieldset>
</form>
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
..................
@{Html.RenderPartial("YourPartialView");}
..................
@await Component.InvokeAsync("Contact")
..................
@section Scripts {
<script>
//Do somthing
</script>
}
Default.cshtml:
public class ContactViewComponent : ViewComponent
{
public IViewComponentResult Invoke()
{
return View();
}
}
/Views/[CurrentController]/Components/[NameOfComponent]/Default.cshtml
/Views/Shared/Components/[NameOfComponent]/Default.cshtml
@model ViewComponentTest.ViewModels.Contact.ContactViewModel
<form method="post" asp-action="contact" asp-controller="home">
<fieldset>
<legend>Contact</legend>
Email: <input asp-for="Email" /><br />
Name: <input asp-for="Name" /><br />
Message: <textarea asp-for="Message"></textarea><br />
<input type="submit" value="Submit" class="btn btn-default" />
</fieldset>
</form>
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
..................
@{Html.RenderPartial("YourPartialView");}
..................
@await Component.InvokeAsync("Contact")
..................
@section Scripts {
<script>
//Do somthing
</script>
}
@model ViewComponentTest.ViewModels.Contact.ContactViewModel
接触
电子邮件:
名称:
消息:
\u Layout.cshtml:
<!DOCTYPE html>
<html>
<head>
...
@RenderSection("styles", required: false)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
</head>
<body>
@RenderBody()
...
//script move to head
@RenderSection("scripts", required: false)
</body>
</html>
...
@RenderSection(“样式”,必填项:false)
@RenderBody()
...
//脚本移到头部
@RenderSection(“脚本”,必需:false)
View.cshtml:
public class ContactViewComponent : ViewComponent
{
public IViewComponentResult Invoke()
{
return View();
}
}
/Views/[CurrentController]/Components/[NameOfComponent]/Default.cshtml
/Views/Shared/Components/[NameOfComponent]/Default.cshtml
@model ViewComponentTest.ViewModels.Contact.ContactViewModel
<form method="post" asp-action="contact" asp-controller="home">
<fieldset>
<legend>Contact</legend>
Email: <input asp-for="Email" /><br />
Name: <input asp-for="Name" /><br />
Message: <textarea asp-for="Message"></textarea><br />
<input type="submit" value="Submit" class="btn btn-default" />
</fieldset>
</form>
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
..................
@{Html.RenderPartial("YourPartialView");}
..................
@await Component.InvokeAsync("Contact")
..................
@section Scripts {
<script>
//Do somthing
</script>
}
@{
Layout=“~/Views/Shared/_Layout.cshtml”;
}
..................
@{Html.RenderPartial(“YourPartialView”);}
..................
@wait Component.InvokeAsync(“联系人”)
..................
@节脚本{
//干坏事
}
查看组件的方式:(您可以查看更多信息)
@section脚本不会在ViewComponent、view component中呈现
应该能够在@section中包含脚本
作为组件的部分视图可以跨多个视图和
组件负责自己的功能
我决定写一个ScriptTagHelper,它提供一个“OnContentLoaded”属性。如果为true,则我使用Javascript函数包装脚本标记的内部内容,以便在文档准备就绪后执行。这避免了当ViewComponent的脚本启动时jQuery库尚未加载的问题
[HtmlTargetElement("script", Attributes = "on-content-loaded")]
public class ScriptTagHelper : TagHelper
{
/// <summary>
/// Execute script only once document is loaded.
/// </summary>
public bool OnContentLoaded { get; set; } = false;
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (!OnContentLoaded)
{
base.Process(context, output);
}
else
{
var content = output.GetChildContentAsync().Result;
var javascript = content.GetContent();
var sb = new StringBuilder();
sb.Append("document.addEventListener('DOMContentLoaded',");
sb.Append("function() {");
sb.Append(javascript);
sb.Append("});");
output.Content.SetHtmlContent(sb.ToString());
}
}
}
[HtmlTargetElement(“脚本”,Attributes=“on content loaded”)]
公共类ScriptTagHelper:TagHelper
{
///
///仅在加载文档后执行脚本。
///
public bool OnContentLoaded{get;set;}=false;
公共覆盖无效进程(TagHelperContext上下文,TagHelperOutput输出)
{
如果(!OnContentLoaded)
{
过程(上下文、输出);
}
其他的
{
var content=output.GetChildContentAsync().Result;
var javascript=content.GetContent();
var sb=新的StringBuilder();
sb.追加(“document.addEventListener('DOMContentLoaded',”);
sb.Append(“函数(){”);
sb.Append(javascript);
某人加上(“}”);”;
output.Content.SetHtmlContent(sb.ToString());
}
}
}
ViewComponent中的用法示例:
<script type="text/javascript" on-content-loaded="true">
$('.button-collapse').sideNav();
</script>
$('.button collapse').sideNav();
可能还有比这更好的方法,但到目前为止,这对我来说很有效。这是我正在使用的解决方案。它支持外部脚本加载和自定义内联脚本。虽然某些设置代码需要放入布局文件(例如_layout.cshtml),但所有内容都是从视图组件中编排的 布局文件:
public class ContactViewComponent : ViewComponent
{
public IViewComponentResult Invoke()
{
return View();
}
}
/Views/[CurrentController]/Components/[NameOfComponent]/Default.cshtml
/Views/Shared/Components/[NameOfComponent]/Default.cshtml
@model ViewComponentTest.ViewModels.Contact.ContactViewModel
<form method="post" asp-action="contact" asp-controller="home">
<fieldset>
<legend>Contact</legend>
Email: <input asp-for="Email" /><br />
Name: <input asp-for="Name" /><br />
Message: <textarea asp-for="Message"></textarea><br />
<input type="submit" value="Submit" class="btn btn-default" />
</fieldset>
</form>
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
..................
@{Html.RenderPartial("YourPartialView");}
..................
@await Component.InvokeAsync("Contact")
..................
@section Scripts {
<script>
//Do somthing
</script>
}
将其添加到页面顶部附近(在
标记内是一个好地方):
MYCOMPANY=window.MYCOMPANY |{};
MYCOMPANY.delayed=null;
MYCOMPANY.delay=function(f){var e=MYCOMPANY.delayed;MYCOMPANY.delayed=e?function(){e();f();}:f;};
将其添加到页面底部附近(就在关闭
标记之前是一个好地方):
MYCOMPANY.delay=函数(f){setTimeout(f,1)};if(MYCOMPANY.delayed){MYCOMPANY.delay(MYCOMPANY.delayed);MYCOMPANY.delayed=null;}
查看组件:
public class ContactViewComponent : ViewComponent
{
public IViewComponentResult Invoke()
{
return View();
}
}
/Views/[CurrentController]/Components/[NameOfComponent]/Default.cshtml
/Views/Shared/Components/[NameOfComponent]/Default.cshtml
@model ViewComponentTest.ViewModels.Contact.ContactViewModel
<form method="post" asp-action="contact" asp-controller="home">
<fieldset>
<legend>Contact</legend>
Email: <input asp-for="Email" /><br />
Name: <input asp-for="Name" /><br />
Message: <textarea asp-for="Message"></textarea><br />
<input type="submit" value="Submit" class="btn btn-default" />
</fieldset>
</form>
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
..................
@{Html.RenderPartial("YourPartialView");}
..................
@await Component.InvokeAsync("Contact")
..................
@section Scripts {
<script>
//Do somthing
</script>
}
现在,您可以在代码中的任何位置(包括视图组件)执行此操作,并在页面底部执行脚本:
<script>
MYCOMPANY.delay(function() {
console.log('Hello from the bottom of the page');
});
</script>
MYCOMPANY.delay(函数(){
log(“页面底部的Hello”);
});
具有外部脚本依赖关系 但有时这还不够。有时,您需要加载外部JavaScript文件,并且只在加载外部文件后执行自定义脚本。您还希望在视图组件中协调这一切,以实现完全封装。为此,我在布局页面(或外部Java)中添加了更多的设置代码