我应该在哪里包含视图组件的脚本?

Where should I include a script for a view component?

我试过在视图组件的视图中添加部分脚本。

@section scripts {
    <script src="~/somepath" asp-append-version="true"></script>
}

我在共享布局中也有渲染部分

@RenderSection("scripts", required: false)

在项目的部分视图和其他地方使用时,脚本加载正常。但是,当在视图组件中时,脚本不会加载。

我想我可以将脚本包含在调用该组件的每个视图的部分标记中。我觉得这不符合视图组件的自包含性质。

还有其他方法吗?

据我所见,ViewComponent 中的 "@section Scripts {}" 被忽略并且不会在 ViewComponents _*layout.cshtml

的相关 @RenderSection() 中呈现

我不知道这是为什么。

我在 viewcomponents 中的 sections 标签也有问题。事实证明,据我所知,viewcomponents 不支持它。参见 https://github.com/aspnet/Home/issues/2037

Jake Shakesworth 实现了一个标签助手,如下所示: Javascript in a View Component

另一方面,您可以将它作为

包含在视图组件中
<script defer src"...">
  </script>

我的要求是从视图组件显示 google 地图。问题是脚本在 jquery、jquery.ui 之前被调用。
通过使用延迟,您告诉解析器在文档加载之前不要执行它,从而避免了必须将它放在布局中才能正确执行的问题。 chrome、safari 和 ie(10+)、ff(3.6+)、o(15+)

支持 Defer

希望对您有所帮助

这是我的代码示例:

@using MobileVet.WebApp.Services;
@inject ISettingsService SettingsService
@{
     var Options = SettingsService.Value();

    <!--Service Area-->
    <div class="container-fluid">
         <div class="row p-3">
            <!--First column-->
            <div class="col-md-3">
                <h5 class="title">Site Navigation</h5>
                <ul>
                    <li><a href="#!">Home</a></li>
                    <li><a href="#!">Services</a></li>
                    <li><a href="#!">Link 3</a></li>
                    <li><a href="#!">Link 4</a></li>
                </ul> 

            </div>
            <!--/.First column-->
            <hr class="w-100 clearfix d-md-none">

            <!--Second column-->
            <div class="col-md-9">

                <div id="map-canvas" style="min-height: 300px; min-width: 200px;"> 
                </div>
            </div>
            <!--/.Second column-->

        </div>
    </div>
    <!--Service Area-->


<script src="http://maps.google.com/maps/api/js?key=XXXXXXXXXXXXXXXXXXXXXXX&sensor=false"></script>
<script type="text/javascript" src="~/js/components/servicearea.js" defer ></script>

}

请注意,如果视图组件在页面上多次出现,您可能需要编写一些逻辑来防止脚本被多次包含,而我的情况并非如此

这就是我使用 Asp.net 核心 2.0.

将脚本插入视图组件的方法

首先,我创建了一个局部视图,并将其放置在视图组件视图文件夹中。

路径:Views/Shared/Components/CalendarWidget/_CalendarScriptsPartial.cshtml

_CalendarScriptsPartial.cshtml

<environment include="Development">
    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/moment/moment.js"></script>
    <script src="~/lib/fullcalendar/dist/fullcalendar.js"></script>
    <script src="~/js/calendarWidget.js"></script>
</environment>
<environment exclude="Development">
    <script src="~/lib/jquery/dist/jquery.min.js"></script>
    <script src="~/lib/moment/min/moment.min.js"></script>
    <script src="~/lib/fullcalendar/dist/fullcalendar.min.js"></script>
    <script src="~/js/calendarWidget.js"></script>
</environment>

然后,我通过视图组件视图中的 Html 部分异步辅助方法引入了脚本。

路径:Views/Shared/Components/CalendarWidget/Default.cshtml

Default.cshtml

<section id="calendar"></section>
@await Html.PartialAsync( "Components/CalendarWidget/_CalendarScriptsPartial" )

为了完整起见,这里是我的视图组件 class。

路径:ViewComponents/CalendarWidgetViewComponent.cs

CalendarWidgetViewComponent.cs

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

namespace LodgersChoice.ViewComponents
{
    public class CalendarWidgetViewComponent : ViewComponent
    {
        public async Task<IViewComponentResult> InvokeAsync( )
        {
            return View( );
        }
    }
}

注意:我的示例目前不需要异步,但我打算将存储库注入 class 的构造函数,它将使用 async/await.

注意 2:完成开发后,我计划将所有内容捆绑并缩小到一个脚本中。

ASP.NET 中的视图组件 Core 就像独立视图和独立控制器一样,因此您可以在视图组件上方插入波纹管标签

@{
Layout = null;
}

之后插入波纹管标签以使用相关脚本,例如:

<environment include="Development">

<script src="~/js/chart.js"></script>

</environment>
 <environment exclude="Development">

<script src="~/js/chart.min.js"></script>

</environment>

@section scripts { } in viewcomponents 被忽略并且不被 Asp.Net 渲染引擎渲染。所以只需在视图组件的末尾使用。此外,如果您的 jquery 脚本在布局的末尾指定,那么 jquery 将在您的视图组件中不可用。当然把jquery脚本移到layout的head部分就可以解决问题,但是建议在最后加载js文件。

所以如果你想在布局的末尾保留 jquery 脚本并且仍然在 viewcomponents 中使用 jquery,你可以使用 javascript domcontentloaded 并且任何 jquery 都可以写在domcontentloaded里面。这不是一个永久的好方法,但对我有用。

<script>
    document.addEventListener('DOMContentLoaded', function (event) {
        console.log($ === jQuery)
    });
</script>

或者如@Alberto L. Bonfiglio 所述,您也可以尝试将脚本移动到另一个 JS 文件并延迟将其加载到视图组件中:

<script src="viewComponentScript.js" defer></script>

我在范围服务中注册 ViewComponents 脚本,然后在布局中的脚本部分之后呈现注册的脚本。

ViewComponentsService.cs

using System;
using System.Collections.Generic;

namespace YourProject.Services
{
    public class ViewComponentsService
    {
        
        private readonly List<Func<object>> _scripts = new List<Func<object>>();

        public IEnumerable<Func<object>> Scripts {
            get { 
                foreach (var script in _scripts)
                {
                    yield return script;
                }
            }
        }
        
        // A dictionary could be used as type for the _scripts collection.
        // Doing so a script Id could be passed to RegisterScript.
        // Usefull if only one script per ViewComponent type needs to be rendered.
        public void RegisterScript(Func<object> script) {
            _scripts.Add(script);
        }

    }
}

不要忘记在启动时注册服务。

services.AddScoped<ViewComponentsService>();

示例视图组件

这里我们有 ViewComponent 及其脚本在同一个文件

@model UI.FailUserFeedback
@inject Services.ViewComponentsService _viewComponentsService

@{
    var modalId = UI.Utilities.RandomId();
    var labelId = UI.Utilities.RandomId();
}

<div class="modal fade" id="@modalId" tabindex="-1" aria-labelledby="@labelId" aria-hidden="true">
    @*omitted for brevity*@
</div>

@{
    // the script is written here
    Func<dynamic, object> RenderScript =
    @<script>
            (function () {
                var modal = new bootstrap.Modal(document.getElementById('@modalId'));
                modal.show();
            })();
    </script>;
    // and registered here
    _viewComponentsService.RegisterScript(() => RenderScript(this));
}

布局

@inject Services.ViewComponentsService _viewComponentsService
...
@await RenderSectionAsync("Scripts", required: false)
@foreach(var script in _viewComponentsService.Scripts) {
    @script();
}

如果 ViewComponent 在页面完全加载后由模式内部的 Controller 调用或呈现另一个元素,则 defer 也将不起作用。相反,您必须将这些脚本放在父视图或 _Layout 中。 在我的例子中,它是一个 ajax 形式和

<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
<script src="~/lib/jquery-ajax-unobtrusive/jquery.unobtrusive-ajax.js"></script>

甚至@{await Html.RenderPartialAsync("_ValidationScriptsPartial");} 将无法加载并导致正确发布表单时出现问题。