在 Blazor 中,我使用
NavigationManager.NavigateTo(url)
来更改窗口位置,但如何在不需要在 OnAfterRenderAsync()
上调用 JS 的情况下使用它来打开一个指定 URL 的新标签页呢?截至2022年6月1日,目前没有使用纯Blazor直接处理它的方法,您需要使用JSInterop。幸运的是,这很容易实现。在您的.razor
文件顶部添加以下内容:
@inject IJSRuntime JSRuntime;
然后像这样使用它
await JSRuntime.InvokeAsync<object>("open", url, "_blank");
请注意,IJSRuntime
接口本身仅提供 InvokeAsync<TValue>
方法,而 JSRuntimeExtensions
类则提供了一个扩展方法,用于在不返回值的情况下直接调用方法:InvokeVoidAsync
await JSRuntime.InvokeVoidAsync("open", url, "_blank");
以前这段代码是可以工作的。
await _jsRuntime.InvokeVoidAsync("open", new object[2] { url, "_blank" });
目前,它会导致未捕获的异常:
> "TypeError: Converting circular structure to JSON
我在此找到了相关解释(https://github.com/dotnet/aspnetcore/issues/16632):
这是因为window.open返回一个WindowProxy对象(请参阅https://developer.mozilla.org/en-US/docs/Web/API/Window/open)。WindowProxy不能被JSON序列化,因此不能用作.NET代码的返回值。
要解决此问题,请不要直接调用window.open,而是调用自己的JS函数,该函数要么不返回任何内容,要么返回可JSON序列化的内容。
根据上述建议,我将以下内容添加到index.html中:
<script>
window.blazorOpen = (args) => {
window.open(args);
};
</script>
我修改了C#的代码,调用时传递窗口参数:
await _jsRuntime.InvokeVoidAsync("blazorOpen", new object[2] { url, "_blank" });
现在我们通过丢弃由window.open返回的WindowProxy对象来有效避免此问题,该对象曾经被返回给InvokeVoidAsync和.NET试图(但未能成功)处理。
await _jsRuntime.InvokeVoidAsync("open", new object[2] { url, "_blank" });
await _jsRuntime.InvokeAsync<object>("open", url, "_blank");
window.open
返回一个WindowProxy
对象(请参见https://developer.mozilla.org/en-US/docs/Web/API/Window/open)。WindowProxy
不可JSON序列化,因此无法作为.NET代码的返回值。await JSRuntime.InvokeVoidAsync("eval", $"let _discard_ = open(`{url}`, `_blank`)");
只需使用常规链接即可
<a href="@Url" target="_blank">@UrlDescription</a>
@onclick="@(async ()=>await JSRuntime.InvokeAsync<object>("open", url, "_blank"))"
- Flexy根据最新的API更改,以下是可将任何自定义对象属性添加到URL的工作解决方案:
/// <summary>
/// Show Link
/// </summary>
/// <returns></returns>
private async Task ShowLink()
{
if (this.selectedItem != null)
{
string url = $"https://example.com/sites/" + this.selectedItem.Id + "/SitePages/Reports/somepage.aspx";
//NavigationManager.NavigateTo(url, false);//opens the new page on same browser tab
string[] values = { url, "_blank" };
CancellationToken token = new CancellationToken(false);
await JSRuntime.InvokeAsync<object>("open", token, values);//opens the link in new browser tab
}
}
以下是具体步骤:
<NavLink class="MyCssClass"
target="_blank"
href="https://www.google.com">
Google in new window
</NavLink>
InvokeVoidAsync
没有在IJSRuntime
接口中指定。我更新了答案以添加该部分。此外,即使查看了源代码,我也不知道InvokeVoidAsync
如何避免异常。也许在我最初发布这个答案和今天之间,在内部修复了这个问题。 - MindSwipe