建议在 _Host.cshtml 中加载 JS 库,而不是在布局 (layout) 中(也不允许在组件 (component) 中加载)。
但这样做,如何为一个页面加载一些脚本文件,为另一个页面加载其它的脚本文件呢?例如,我只想在使用谷歌地图或数据表格的页面中加载它们,而不是在所有页面中都加载(浪费空间/内存/加载时间)。
谢谢!
建议在 _Host.cshtml 中加载 JS 库,而不是在布局 (layout) 中(也不允许在组件 (component) 中加载)。
但这样做,如何为一个页面加载一些脚本文件,为另一个页面加载其它的脚本文件呢?例如,我只想在使用谷歌地图或数据表格的页面中加载它们,而不是在所有页面中都加载(浪费空间/内存/加载时间)。
谢谢!
正如评论中所讨论的那样,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
元素上。它返回一个Promise,因为脚本将异步加载,所以需要在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
还有一种使用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");
}
}
这个方法即使是通过 href 返回页面而不是 Navigationmanager 重定向(强制重新加载为 true)也可以工作。 如果您需要在页面加载时应用一些 js 到 dom 元素,则可以在 "firstrender" 部分中使用 CallJavascriptMethod。