首页 > 解决方案 > 如何在同一个 Razor 页面中使用相同视图组件和 Javascript 文件的多个实例?

问题描述

我有一个剃须刀页面,我将两个或多个相同类型/源的视图组件导入剃须刀页面。视图组件本质上是相同的,但每个实例将从数据库中加载不同的值,具体取决于表单实例上的放置选择以及通过 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>

在此处输入图像描述

标签: javascriptrazor-pagesasp.net-core-viewcomponent.net-5

解决方案


好的,这就是我的工作方式:

首先,我们不想在每个剃须刀页面上多次加载参考 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

这是我创建的一个新类,用于引用一个整数(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,这对我来说不是这样的问题,但可能是一个运行时间很长的应用程序最好在某个时候再次将整数重置为零,这样你就不会得到一个长整数。我会为此想出一个解决方案,然后更新我的答案。

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


推荐阅读