【问题标题】:Blazor Server: load js scripts only on certain pages, not on allBlazor Server:仅在某些页面上加载 js 脚本,而不是在所有页面上
【发布时间】:2020-03-17 11:36:01
【问题描述】:

建议在_Host.cshtml中加载JS库,而不是在布局中(也不在不允许的组件中)

但是这样做,如何为一个页面加载一些脚本而为另一个页面加载一些脚本?例如。我只希望在我使用它们的页面中使用 googlemaps 内容或数据表内容,而不是全部(浪费空间/内存/加载时间)。

谢谢

【问题讨论】:

  • Blazor 是一个 SPA: 页面应用程序。所以只有一页,你需要带上所有东西。 _主机是正确的地方。
  • 但也许你可以用 JS Interop 做一些动态加载,而不是我的领域。
  • “Blazor 是一个 SPA:单页应用程序”那么……Angular 也是一个 SPA。 “所以只有一页,你需要带上所有东西”你说什么???
  • @SandroRiz,请耐心等待。它很快就会到来。有人告诉我,它将像 Angular 一样实施。

标签: blazor


【解决方案1】:

正如 cmets 中所讨论的,Blazor 是一个 SPA,因此任何加载的脚本都可以在 Blazor 页面上使用,因为它是同一个页面。

但是,您必须_Host.cshtml 中将它们全部列出,实际上您可能只想在需要时加载特定脚本(例如,并非所有用户都使用特定页面/需要脚本的组件)。

可以使用 JS Interop 动态加载脚本。我创建了以下scriptLoader.js 库并将其包含在_Host.cshtml 中:

// loadScript: returns a promise that completes when the script loads
window.loadScript = function (scriptPath) {
    // check list - if already loaded we can ignore
    if (loaded[scriptPath]) {
        console.log(scriptPath + " already loaded");
        // return 'empty' promise
        return new this.Promise(function (resolve, reject) {
            resolve();
        });
    }

    return new Promise(function (resolve, reject) {
        // create JS library script element
        var script = document.createElement("script");
        script.src = scriptPath;
        script.type = "text/javascript";
        console.log(scriptPath + " created");

        // flag as loading/loaded
        loaded[scriptPath] = true;

        // if the script returns okay, return resolve
        script.onload = function () {
            console.log(scriptPath + " loaded ok");
            resolve(scriptPath);
        };

        // if it fails, return reject
        script.onerror = function () {
            console.log(scriptPath + " load failed");
            reject(scriptPath);
        }

        // scripts will load at end of body
        document["body"].appendChild(script);
    });
}
// store list of what scripts we've loaded
loaded = [];

这将创建一个script 元素并附加到文档的body 元素。它返回一个承诺,因为脚本将异步加载,因此您需要在 C# 代码中使用await

loaded 数组用于避免再次重新加载脚本。任何脚本一旦加载,就会保持加载状态,除非用户刷新页面。所以负载只发生一次。

在我需要确保加载库的页面/组件上,我需要注入 IJSruntime...

@inject IJSRuntime jsRuntime

然后调用它..

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        // invoke script loader
        Console.WriteLine("Loading jQuery");
        await jsRuntime.InvokeVoidAsync("loadScript", "https://code.jquery.com/jquery-3.4.1.js");
        await jsRuntime.InvokeVoidAsync("loadScript", "myJQueryTest.js");

        Console.WriteLine("Invoking jQuery");

        await jsRuntime.InvokeVoidAsync("setH1", "Hello world!");

        Console.WriteLine("Invoked JQuery");

        await base.OnAfterRenderAsync(firstRender);
    }

myJQueryTest.js 很简单:

window.setH1 = function (message) {
    $('h1').text(message);
}

已创建演示代码库:https://github.com/conficient/BlazorDynamicScriptLoad

【讨论】:

  • 我应该补充一下,这是一个非常粗略的演示 - 更好的错误处理是个好主意
  • 另一个注意事项 - 我使用一个复杂的库进行了测试,该库还加载了自己的脚本,但失败了,因此它可能不适用于所有情况。对于简单的用例应该没问题。
  • 您是否尝试过刷新页面,您的动态脚本加载出现在哪里?只要我不刷新页面,我非常相似的代码确实可以正常工作,当我这样做时 - 整个应用程序不再正确反应。我期待使用你的代码,但无法让它在 atm 中使用
  • 我会检查日志/控制台是否有错误,您不必刷新页面
  • 嘿,我也花了一些时间-稍后会提供详细信息,但在这里我的发现:是的,它可以在没有重新加载的情况下工作,如前所述。当我告诉他“不需要刷新”时,一个典型的用户会失去信任......我知道它仍然是以前的。所以但是!当我访问第一页时,另一个具有相同技术的第二页不起作用
【解决方案2】:

还有另一种方法可以在 JavaScript 中使用导出的函数

wwwroot/js/script.js

export async function someFunction(parameter1, paramater2) {
        ...
  }

Pages/CallJavaScript.razor

@page "/call-js"
@inject IJSRuntime JS

@code{
  private IJSObjectReference myScript;

  protected override async Task OnAfterRenderAsync(bool firstRender)
  {
    if (firstRender)
    {
      myScript = await JS.InvokeAsync<IJSObjectReference>("import", "/js/script.js");
    }
  }

  private async Task CallJavaScriptMethod()
  {
    myScript.InvokeVoidAsync("someFunction", "param1", "param2");
  }

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多