Blazor 启用动态根组件/错误:此应用程序中尚未启用动态根组件

Xed*_*don 4 javascript c# blazor

我想从 javascript 渲染 Blazor 组件。请参阅https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-rc-1/ “从 JavaScript 渲染 Blazor 组件”

我有一个 HTML 文件:

<script src="/_framework/blazor.server.js"></script>
<div id="counter"></div>

<script>
    async function ready() {
        let containerElement = document.getElementById('counter');
        await Blazor.rootComponents.add(containerElement, 'counter', { incrementAmount: 10 });
    }
    document.addEventListener("DOMContentLoaded", ready);
</script>
Run Code Online (Sandbox Code Playgroud)

并做

builder.Services.AddServerSideBlazor(options =>
{
    options.RootComponents.RegisterForJavaScript<Counter>("counter");
});
Run Code Online (Sandbox Code Playgroud)

错误消息(JavaScript):

test.html:14 Uncaught (in promise) Error: Dynamic root components have not been enabled in this application.
    at E (blazor.server.js:1)
    at Object.add (blazor.server.js:1)
    at HTMLDocument.ready (test.html:8)
Run Code Online (Sandbox Code Playgroud)

如何启用动态根组件?

Mis*_*goo 8

发生错误的原因是文档加载和 Blazor“准备好”处理您添加组件的请求之间存在延迟。

似乎没有任何官方记录的解决方案,但类似的事情是可能的

将 Blazor 更改为手动启动:

索引.html

<script src="_framework/blazor.webassembly.js" autostart="false"></script>
<script src="js/script.js" defer></script>
Run Code Online (Sandbox Code Playgroud)

启动 Blazor,然后尝试添加组件 - 重复直到成功

脚本.js

document.addEventListener("DOMContentLoaded", startBlazor)

function startBlazor() {
    Blazor
        .start()
        .then(() => {
            requestAnimationFrame(AddBlazorComponents)
        })
        .catch((error) => console.error(error));
}

let attempts = 0
const maxAttempts = 120 // arbitrary choice

function AddBlazorComponents() {
    if (attempts > maxAttempts) {
        // give up after trying too many times
        console.error("Could not load Blazor components.")
        return
    }

    const containerElement = document.querySelector('#app')
    Blazor.rootComponents.add(containerElement, 'app', {})
        .catch(reason => {
            if (reason.message === "Dynamic root components have not been enabled in this application.")
                requestAnimationFrame(AddBlazorComponents)
            else
                console.error(reason)
        })
    attempts++
}
Run Code Online (Sandbox Code Playgroud)

更好的解决方案?

您可以在应用程序启动后向您的 .NET 代码添加 JSInterop 调用以促进这一点 - 但对于不同的托管模型:Blazor Server / Blazor WebAssembly 会有所不同。

更好的方法可能是通过预先注册组件的方法向 aspnetcore 存储库发出 PR,以便框架在准备就绪时加载。

2021 年 9 月 29 日更新

事实证明,有一些当前未记录的功能可以在这里提供帮助。我复制了来自 @Swimburger 的github 问题的评论:

对于动态组件来说,新的 JavaScript 初始化程序afterStarted被调用(可能)太早,但事实证明您可以传递一个初始化程序来为动态组件调用 - 但它没有很好的文档记录或直观的恕我直言。

为了实现此目的,我在program.cs中更改了应用程序启动(添加javaScriptInitializer: "loadApp"):

builder.RootComponents.RegisterForJavaScript<App>(identifier: "app", javaScriptInitializer: "loadApp");

然后,这就是不直观的地方,我向我的模块(如afterStarted)添加了一个名为loadApp- 但它没有被调用的导出。

事实证明,loadApp只有将其添加到window对象中才能找到,因此我将其添加到了index.html中

<script src="_framework/blazor.webassembly.js"></script>
<script>
    window.loadApp = function (component,params) {
        let containerElement = document.querySelector('#app')
        window.Blazor.rootComponents.add(containerElement, component, params)
    }
</script>
Run Code Online (Sandbox Code Playgroud)

这感觉就像我在如何导出自定义初始值设定项方面遗漏了一些内容,或者确实需要直接添加它window,这看起来很奇怪......