好的,我就是这样解决的:
首先,我们不想在每个 razor 页面上多次加载参考 JavaScript 文件,我相信浏览器在这一点上有一些智能,但是为了整理我最初问题中的代码,让我们移动脚本一直到 Razor 代码块下面:
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
这是我创建的一个新类,用于引用一个整数 (Counter),每次加载视图组件的新实例时我们都会递增该整数。
接下来我们创建一个小型公共类:
namespace MyProject.Models.EventsMonitor
{
public class EventsMonitorViewModel
{
public int Counter { get; set; }
}
}
现在在 ViewComponent.cs 文件中,我们修改返回视图的方法:
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 文件(Default.cshtml 文件)中,我们修改了我们将使用 JavaScript 与之交互的每个 razor/html 组件的 ID。我不打算包含整个文件,但下面显示了剃刀表单的示例部分(您可以在我在原始问题中显示的图像中看到这些下拉选择框):
@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,该 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 View Component 上的下拉选择产生和 Id "pluginTypeSelect1" 和 RHS View Component 产生和 Id "pluginTypeSelect2"
我还没有解决的唯一部分是“计数器”变量将在每次加载 Razor 页面时不断增加 +1,这对我来说不是这样的问题,但可能是一个运行时间很长的应用程序最好在某个时候再次将整数重置为零,这样你就不会得到一个长整数。我会为此想出一个解决方案,然后更新我的答案。
希望这可以帮助遇到类似难题的其他人...