Blazor Server: load js scripts only on certain pages, not on all

前端 未结 1 1118
醉酒成梦
醉酒成梦 2021-01-18 09:37

It is recommended to load JS libraries in the _Host.cshtml and not in the layout (nor in component where is not allowed)

But doing so, how is it possible to load som

1条回答
  •  粉色の甜心
    2021-01-18 10:12

    As discussed in the comments, Blazor is an SPA so any loaded script is available on Blazor pages since it's the same page.

    However, you don't have to list them all in _Host.cshtml, and indeed you probably want to only load a specific script when it's needed (e.g. not all users use a particular page/component where the script is required).

    It is possible to load scripts dynamically using JS Interop. I created the following scriptLoader.js library and included this in _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 = [];
    

    This creates a script element and appends to the body element of the document. It returns a promise since the script will load asynchronously, so you need await in the C# code.

    The loaded array is there to avoid re-loading the script again. Any script, once loaded, stays loaded unless the user refreshes the page. So the load only occurs once.

    On a page/component where I need to ensure a library is loaded, I will need to inject the IJSruntime...

    @inject IJSRuntime jsRuntime
    

    And then call it..

        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);
        }
    

    The myJQueryTest.js is simple:

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

    Demo repo created: https://github.com/conficient/BlazorDynamicScriptLoad

    0 讨论(0)
提交回复
热议问题