繁体   English   中英

如何在同一个 Razor 页面中使用同一视图组件和 Javascript 文件的多个实例?

[英]How to use multiple instances of the same View Component and Javascript files in the same Razor Page?

我有一个 razor 页面,我将两个或多个相同类型/源的视图组件导入 razor 页面。 视图组件本质上是相同的,但每个实例将从数据库中加载不同的值,具体取决于表单实例上的放置选择以及通过 SignalR 来自不同源的流式事件

因为每个视图组件本质上都指向同一个 javascript 文件,所以我发现只有这个视图组件的第一个加载实例是可操作的。

我不确定如何配置 razor 以便它将每个加载的视图组件视为一个单独的实例,因此我可以将视图组件中的每个 razor 表单视为一个单独的实例。 这个问题可能还会影响我有一个 textarea 将由 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 代码块下方:

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 我创建用于引用 integer (计数器),我们将在每次加载视图组件的新实例时递增。

接下来我们创建一个小型公共 class:

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

So in essence, each time we load a new instance of the same View Component, the Razor View is returned with the view model class that we bind to the razor page.

在我的视图组件 Razor 文件(Default.cshtml 文件)中,我们使用 JavaScript 修改每个 razor/html 组件的 ID。 我不打算包含整个文件,但 razor 表单的示例部分如下所示(这些下拉 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,该 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 上的下拉 select 产生和 Id "pluginTypeSelect1" 和 RHS View Component 产生和 Id "pluginTypeSelect2"

我还没有解决的唯一部分是,每次加载 Razor 页面时,“计数器”变量将继续增加 +1,这对我来说不是这样的问题,但可能是一个运行时间很长的应用程序最好在某个时候再次将 integer 重置为零,这样你就不会得到一个长整数。 我会为此想出一个解决方案,然后更新我的答案。

希望这可以帮助遇到类似难题的其他人...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM