如何在同一 Razor 页面中使用同一视图组件和 Javascript 文件的多个实例?
How to use multiple instances of the same View Component and Javascript files in the same Razor Page?
我有一个 razor 页面,我在其中将相同 type/source 的两个或多个视图组件导入到 razor 页面中。视图组件本质上是相同的,但每个实例都会根据表单实例上的放置选择以及通过 SignalR
从不同来源流式传输事件,从数据库中加载不同的值
因为每个视图组件本质上指向同一个 javascript 文件,我发现只有该视图组件的第一个加载实例是可操作的。
我不确定如何配置 razor 以便它将每个加载的视图组件视为一个单独的实例,因此我可以将视图组件中的每个 razor 表单视为一个单独的实例。这个问题也可能会影响我有一个文本区域将由 SignalR
动态更新的事实
<div class="container-fluid h-100 p-0 m-0">
<div class="row justify-content-center h-100 pl-0">
@Html.AntiForgeryToken()
<div class="col-12 col-sm-12 col-md-6">
@await Component.InvokeAsync("EventsMonitor")
<script defer src="~/js/eventsmonitor-custom-scripts/eventsMonitor.js"></script>
</div>
<div class="col-12 col-sm-12 col-md-6 pl-sm-3 pl-md-2 pt-3 pt-sm-3 pt-md-0">
@await Component.InvokeAsync("EventsMonitor")
<script defer src="~/js/eventsmonitor-custom-scripts/eventsMonitor.js"></script>
</div>
</div>
好的,这就是我的计算方法:
首先,我们不想在每个 razor 页面上多次加载参考 JavaScript 文件,我相信浏览器在这一点上有一定的智能,但要整理我的代码原始问题,让我们将脚本向下移动到剃须刀代码块下方:
Razor 页面(将显示同一视图组件的多个实例)
@model MyProject.Pages.EventsMonitor.ViewEventsModel
@{
}
<div class="container-fluid h-100 p-0 m-0">
<div class="row justify-content-center h-100 pl-0">
@Html.AntiForgeryToken()
<div class="col-12 col-sm-12 col-md-6">
@await Component.InvokeAsync("EventsMonitor")
</div>
<div class="col-12 col-sm-12 col-md-6 pl-sm-3 pl-md-2 pt-3 pt-sm-3 pt-md-0">
@await Component.InvokeAsync("EventsMonitor")
</div>
</div>
</div>
<!-- By using 'defer' you are telling the parser not to execute
it until the document had loaded thus avoiding the problem
of the having to put it in the layout for proper execution.
Defer is supported by chrome, safari, and ie(10+), ff(3.6+), o(15+) -->
<script defer src="~/js/eventsmonitor-custom-scripts/eventsMonitor.js"></script>
在上面,您会看到我们引用了
@model MyProject.Pages.EventsMonitor.ViewEventsModel
这是我为引用一个整数(计数器)而创建的新 class,每次我们加载视图组件的新实例时,我们都会递增它。
接下来我们创建一个小的 public class:
namespace MyProject.Models.EventsMonitor
{
public class EventsMonitorViewModel
{
public int Counter { get; set; }
}
}
现在在 ViewComponent.cs 文件中,我们修改 returns 视图的方法:
namespace MyProject.ViewComponents
{
public class EventsMonitor : ViewComponent
{
[BindProperty] // Bind to the small class we created in previous step.
public EventsMonitorViewModel EventsMonitorViewModel { get; set; }
private static int _value = 0;
public IViewComponentResult Invoke()
{
var EventsMonitorViewModel = new EventsMonitorViewModel
{
// See MS Link in notes for an increment function.
Counter = Interlocked.Increment(ref _value)
};
return View(EventsMonitorViewModel);
}
}
}
递增的 MS 指南在这里:https://docs.microsoft.com/en-us/dotnet/api/system.threading.interlocked.increment?view=net-5.0
所以本质上,每次我们加载同一视图组件的新实例时,Razor 视图都会返回我们绑定到 razor 页面的视图模型 class。
在我的 View Component Razor 文件(Default.cshtml 文件)中,我们修改了我们将使用 JavaScript 与之交互的每个 razor/html 组件的 ID。我不打算包括整个文件,但下面显示了剃刀表单的示例部分(这些下拉框 select 您可以在我在原始问题中显示的图像中看到):
@model WebApp_PLUGIN.Models.EventsMonitor.EventsMonitorViewModel
<div class="form-group" style="margin-top: 1.5em">
<div class="row">
<div class="col-sm">
<label class="control-label">Plugin Type</label>
<select class="form-control" id="@("pluginTypeSelect"+Model.Counter)" onchange="pluginTypeSelect(this.id)">
<option value="">Select</option>
<option value="RS232Port">RS232 Port</option>
<option value="SmtpServer">SMTP Server</option>
<option value="TcpClient">TCP Client</option>
<option value="TcpServer">TCP Server</option>
</select>
</div>
<div class="col-sm mt-sm-0 mt-3">
<label class="control-label">Source</label>
<select class="form-control" id="@("pluginSourceSelect"+Model.Counter)">
<option value="">Select</option>
</select>
</div>
</div>
<div class="text-danger" id="@("eventsMonitorMessageBarTop"+Model.Counter)" style="white-space: pre-line"></div>
</div>
</div>
在上面的 Razor 代码块中,对于每个元素 Id,我们将计数器变量添加到 Id 字符串的末尾,以便在加载视图组件的每个实例时,每个元素都有一个唯一的 Id,向上递增+1.
所以以上所有的结果是当使用 JavaScript 函数作为 razor 中 UI 组件的逻辑时,每个视图组件和关联的表单元素将有一个唯一的 ID。
下面的示例 JavaScript 代码用于测试:
function pluginTypeSelect(clicked_id) {
// Each dropown select from each instance of the View Component will have a unique Id
alert(clicked_id)
}
在我的测试中,参考我原始问题中的屏幕截图,LHS 视图组件上的下拉列表 select 生成了 Id“pluginTypeSelect1”,RHS 视图组件生成了 Id“pluginTypeSelect2”
我唯一没有解决的部分是每次加载 Razor 页面时“Counter”变量都会递增 +1,这对我来说不是问题,但可能需要很长时间运行 app 最好在某个时候再次将整数重置为零,这样你就不会得到一个 long int。我会想出一个解决方案,然后更新我的答案。
希望这能帮助遇到类似难题的其他人...
我有一个 razor 页面,我在其中将相同 type/source 的两个或多个视图组件导入到 razor 页面中。视图组件本质上是相同的,但每个实例都会根据表单实例上的放置选择以及通过 SignalR
从不同来源流式传输事件,从数据库中加载不同的值因为每个视图组件本质上指向同一个 javascript 文件,我发现只有该视图组件的第一个加载实例是可操作的。
我不确定如何配置 razor 以便它将每个加载的视图组件视为一个单独的实例,因此我可以将视图组件中的每个 razor 表单视为一个单独的实例。这个问题也可能会影响我有一个文本区域将由 SignalR
动态更新的事实<div class="container-fluid h-100 p-0 m-0">
<div class="row justify-content-center h-100 pl-0">
@Html.AntiForgeryToken()
<div class="col-12 col-sm-12 col-md-6">
@await Component.InvokeAsync("EventsMonitor")
<script defer src="~/js/eventsmonitor-custom-scripts/eventsMonitor.js"></script>
</div>
<div class="col-12 col-sm-12 col-md-6 pl-sm-3 pl-md-2 pt-3 pt-sm-3 pt-md-0">
@await Component.InvokeAsync("EventsMonitor")
<script defer src="~/js/eventsmonitor-custom-scripts/eventsMonitor.js"></script>
</div>
</div>
好的,这就是我的计算方法:
首先,我们不想在每个 razor 页面上多次加载参考 JavaScript 文件,我相信浏览器在这一点上有一定的智能,但要整理我的代码原始问题,让我们将脚本向下移动到剃须刀代码块下方:
Razor 页面(将显示同一视图组件的多个实例)
@model MyProject.Pages.EventsMonitor.ViewEventsModel
@{
}
<div class="container-fluid h-100 p-0 m-0">
<div class="row justify-content-center h-100 pl-0">
@Html.AntiForgeryToken()
<div class="col-12 col-sm-12 col-md-6">
@await Component.InvokeAsync("EventsMonitor")
</div>
<div class="col-12 col-sm-12 col-md-6 pl-sm-3 pl-md-2 pt-3 pt-sm-3 pt-md-0">
@await Component.InvokeAsync("EventsMonitor")
</div>
</div>
</div>
<!-- By using 'defer' you are telling the parser not to execute
it until the document had loaded thus avoiding the problem
of the having to put it in the layout for proper execution.
Defer is supported by chrome, safari, and ie(10+), ff(3.6+), o(15+) -->
<script defer src="~/js/eventsmonitor-custom-scripts/eventsMonitor.js"></script>
在上面,您会看到我们引用了
@model MyProject.Pages.EventsMonitor.ViewEventsModel
这是我为引用一个整数(计数器)而创建的新 class,每次我们加载视图组件的新实例时,我们都会递增它。
接下来我们创建一个小的 public class:
namespace MyProject.Models.EventsMonitor
{
public class EventsMonitorViewModel
{
public int Counter { get; set; }
}
}
现在在 ViewComponent.cs 文件中,我们修改 returns 视图的方法:
namespace MyProject.ViewComponents
{
public class EventsMonitor : ViewComponent
{
[BindProperty] // Bind to the small class we created in previous step.
public EventsMonitorViewModel EventsMonitorViewModel { get; set; }
private static int _value = 0;
public IViewComponentResult Invoke()
{
var EventsMonitorViewModel = new EventsMonitorViewModel
{
// See MS Link in notes for an increment function.
Counter = Interlocked.Increment(ref _value)
};
return View(EventsMonitorViewModel);
}
}
}
递增的 MS 指南在这里:https://docs.microsoft.com/en-us/dotnet/api/system.threading.interlocked.increment?view=net-5.0
所以本质上,每次我们加载同一视图组件的新实例时,Razor 视图都会返回我们绑定到 razor 页面的视图模型 class。
在我的 View Component Razor 文件(Default.cshtml 文件)中,我们修改了我们将使用 JavaScript 与之交互的每个 razor/html 组件的 ID。我不打算包括整个文件,但下面显示了剃刀表单的示例部分(这些下拉框 select 您可以在我在原始问题中显示的图像中看到):
@model WebApp_PLUGIN.Models.EventsMonitor.EventsMonitorViewModel
<div class="form-group" style="margin-top: 1.5em">
<div class="row">
<div class="col-sm">
<label class="control-label">Plugin Type</label>
<select class="form-control" id="@("pluginTypeSelect"+Model.Counter)" onchange="pluginTypeSelect(this.id)">
<option value="">Select</option>
<option value="RS232Port">RS232 Port</option>
<option value="SmtpServer">SMTP Server</option>
<option value="TcpClient">TCP Client</option>
<option value="TcpServer">TCP Server</option>
</select>
</div>
<div class="col-sm mt-sm-0 mt-3">
<label class="control-label">Source</label>
<select class="form-control" id="@("pluginSourceSelect"+Model.Counter)">
<option value="">Select</option>
</select>
</div>
</div>
<div class="text-danger" id="@("eventsMonitorMessageBarTop"+Model.Counter)" style="white-space: pre-line"></div>
</div>
</div>
在上面的 Razor 代码块中,对于每个元素 Id,我们将计数器变量添加到 Id 字符串的末尾,以便在加载视图组件的每个实例时,每个元素都有一个唯一的 Id,向上递增+1.
所以以上所有的结果是当使用 JavaScript 函数作为 razor 中 UI 组件的逻辑时,每个视图组件和关联的表单元素将有一个唯一的 ID。 下面的示例 JavaScript 代码用于测试:
function pluginTypeSelect(clicked_id) {
// Each dropown select from each instance of the View Component will have a unique Id
alert(clicked_id)
}
在我的测试中,参考我原始问题中的屏幕截图,LHS 视图组件上的下拉列表 select 生成了 Id“pluginTypeSelect1”,RHS 视图组件生成了 Id“pluginTypeSelect2”
我唯一没有解决的部分是每次加载 Razor 页面时“Counter”变量都会递增 +1,这对我来说不是问题,但可能需要很长时间运行 app 最好在某个时候再次将整数重置为零,这样你就不会得到一个 long int。我会想出一个解决方案,然后更新我的答案。
希望这能帮助遇到类似难题的其他人...