将 JavaScript 文件嵌入到 Blazor 项目的 .NET 类库中

Eya*_*nik 2 c# asp.net-core blazor blazor-webassembly

我正在开发一个 Blazor 项目,并尝试将其中一个 JavaScript 文件移动到类库,我已阅读以下指南:

  1. https://learn.microsoft.com/en-us/aspnet/core/razor-pages/ui-class?view=aspnetcore-6.0&tabs=visual-studio#consume-content-from-a-referenced-rcl-1
  2. https://learn.microsoft.com/en-us/aspnet/core/blazor/javascript-interoperability/?view=aspnetcore-6.0#load-a-script-from-an-external-javascript-file-js
  3. https://learn.microsoft.com/en-us/aspnet/core/blazor/javascript-interoperability/call-javascript-from-dotnet?view=aspnetcore-6.0#javascript-isolation-in-javascript-modules

我收到以下错误:

浏览器开发者工具

我不确定我缺少什么或者我需要做什么才能让它工作,所以这是我的设置:

事实:

  1. 我在用着.NET 6
  2. 我正在使用 Visual Studio for Mac Version 17.0 Preview (17.0 build 8754)
  3. 解决方案的名称是LinkScreen
  4. 应用项目的名称是Client.Web
  5. 应用程序程序集的名称是LinkScreen.Client.Web
  6. 应用程序默认命名空间的名称是LinkScreen.Client.Web
  7. 该应用程序的托管模型是 Web Assembly。
  8. 类库项目的名称是Client.BrowserInterop
  9. 类库程序集的名称是LinkScreen.Client.BrowserInterop
  10. 类库默认命名空间的名称是LinkScreen.Client.BrowserInterop

项目结构及代码

  1. 在类库中,我有一个screen-capture.js在以下目录下调用的脚本文件wwwroot\scripts,如下所示:

在此输入图像描述

其构建操作设置为“内容”,并将复制到输出目录设置为“不复制”。

  1. 类库像这样引用应用程序:

在此输入图像描述

  1. 我有一个名为的 C# 类ScreenCapture,它包装了 JavaScript 模块,screen-capture.js并返回引用,如下所示:
public static async ValueTask<ScreenCapture> CreateAsync(
        IJSRuntime jsRuntime,
        ElementReference videoTagReference)
    {
        var jsModuleRef = await jsRuntime.InvokeAsync<IJSInProcessObjectReference>("import", "./_content/LinkScreen.Client.BrowserInterop/screen-capture.js").ConfigureAwait(false);

        return new ScreenCapture(jsModuleRef, videoTagReference);
    }
Run Code Online (Sandbox Code Playgroud)

以前我有一个对screen-capture.js内部的引用index.html,就像这样<script src="_content/LinkScreen.Client.BrowserInterop/scripts/screen-capture.js" type="module"></script>,因为我认为需要使用这些IJSRuntime方法,然后 Blazor 频道上的某人启发了我,所以我删除了引用,但现在我仍然通过调用从包装器中得到相同的 404 错误jsRuntime.InvokeAsync

重要的是要注意,当脚本位于wwwroot/scripts应用程序文件夹内时,一切正常。

  1. 我的 program.cs 文件是 .NET 6 Blazor WebAssembly 项目的默认文件,如下所示:
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using LinkScreen.Client.Web;

var builder = WebAssemblyHostBuilder.CreateDefault(args);

builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");

builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });

await builder.Build().RunAsync();
Run Code Online (Sandbox Code Playgroud)

我尝试过但仍然不起作用的事情:

  1. 清理项目,删除 bin 和 obj 目录。
  2. 清除浏览器的缓存并禁用它。
  3. 我尝试过 Safari 和 Chrome,但遇到了完全相同的问题。

Pan*_*vos 8

我只是尝试将自己的组件导出到库并重新发现了最重要的 Blazor WASM 规则:

  • 始终清除 Client bin 和 obj 文件夹。

将文件夹从主项目复制到类库后有效的方法在执行几次后失败了。该bin文件夹似乎仍然包含一些脚本,因此主项目中有效的路径一直有效,直到完全清理删除它们为止。

如果脚本存储在wwwroot/scripts并且您使用:

<script src="./_content/Client.BrowserInterop/scripts/screen-capture.js
Run Code Online (Sandbox Code Playgroud)

您的方法应该在全球范围内可用。

您应该考虑将 JS 隔离与并排组件脚本结合使用,以避免污染 JS 命名空间并使文件夹变得混乱wwwroot

如果您的组件是名称ScreenCapture.razor,请在名为 的同一文件夹中创建一个 JS 模块ScreenCapture.razor.js。您可以将其作为模块加载到组件中OnAfterRenderAsync并调用其导出方法:

private IJSObjectReference? module;

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if(module ==null)
    {
        var path = "./_content/Client.BrowserInterop/ScreenCapture.razor.js";
        module = await JS.InvokeAsync<IJSObjectReference>("import", path);
    }
}

    private ValueTask SetTextAsync(string text)
    {
        if (module is null)
        {
            return ValueTask.CompletedTask;
        }
        return module.InvokeVoidAsync("setValue", TextBox, text);
    }
Run Code Online (Sandbox Code Playgroud)

例子

我试图使用 JS 隔离将此 TagSelector 组件中的代码放入我自己的 RCL 库中,以保持整洁。CSS 和 JS 文件直接存储,wwwroot所以通常我必须使用:

<link rel="stylesheet" href="_content/MW.Blazor.TagSelector/styles.css" />
<script src="_content/MW.Blazor.TagSelector/interop.js"></script>
Run Code Online (Sandbox Code Playgroud)

通过将文件重命名为TagSelector.razor.cssTagSelector.razor.js,我能够将它们与 Razor 文件放在一起。我现在只需要使用该TagSelector组件。CSS 和 JS 文件会自动导入。

JS 文件已更改为模块:


export function getValue(element) {
    return element.value;
}

export function setValue(element, value) {
    element.value = value;
}

export function blur(element) {
    element.blur();
}
Run Code Online (Sandbox Code Playgroud)

该模块加载有:

var path = "./_content/MyLibraryName/TagSelector.razor.js";
module = await JS.InvokeAsync<IJSObjectReference>("import", path);
Run Code Online (Sandbox Code Playgroud)

要调用导出的setText方法,使用以下包装器:

    private ValueTask SetTextAsync(string text)
    {
        if (module is null)
        {
            return ValueTask.CompletedTask;
        }
        return module.InvokeVoidAsync("setValue", TextBox, text);
    }
Run Code Online (Sandbox Code Playgroud)