在 blazor 应用程序之外使用 blazor 组件(例如,knockoutjs)
Posted
技术标签:
【中文标题】在 blazor 应用程序之外使用 blazor 组件(例如,knockoutjs)【英文标题】:Using blazor components outside of blazor app (eg. knockoutjs) 【发布时间】:2021-10-18 15:22:30 【问题描述】:我正在做一个迁移项目。我是团队中唯一的 JS 开发人员,其余所有人都是 C# 开发人员。 我们正在寻求迁移用 .Net MVC Knockoutjs 编写的现有应用程序。 由于大多数外部团队都是 C# 开发人员,我们正在尝试 blazor。
由于整个应用程序重写需要时间,我们希望以 blazor 组件的形式逐个重写应用程序,并一次导出这些组件以在现有的 knockoutjs 应用程序中重用。
这将使我们能够从淘汰赛过渡到 blazor,同时继续支持和维护现有应用程序。
我将角度元素视为一种方式,但是,就像我提到的那样,我们想尝试一下 blazor。我很好奇我们是否可以将 blazor 组件导出到其他应用程序并允许它们之间的数据流。
感谢任何帮助/建议。
谢谢
【问题讨论】:
只需将每个淘汰页面替换为 blazor 页面?您可以单独执行这些操作;它们不必一次全部转换。 嗯,我的意思是,假设我在 Blazor 中创建了一个新的天气小部件,我想将该小部件作为组件添加到现有的淘汰赛应用程序中,并且从淘汰赛应用程序中,我应该能够搜索任何城市天气..所以数据应该在它们之间流动。 我怀疑是否有一条好的前进道路可以做到这一点。由于 Blazor 是 C#,它所做的很多工作都是服务器端的,而不是客户端的。 这种集成的最大问题是 Blazor 无法看到 DOM 的变化。如果没有 Blazor 跟踪的这些更改,所有电路都无法按预期工作。 Signalr 更新或 webassembly 更新在不一致的环境中应用的风险。从技术上讲,您可以做到,但最好在不混合技术的情况下管理页面。 @RobertHarvey,但是 Blazor WebAssembly 可以纯粹基于浏览器...也就是说,我也怀疑这个用例是否有一条很好的前进道路,但主要是因为 Blazor 有自己的方式做可能会干扰这项技术的事情。 【参考方案1】:如果您想尝试一次用一个 blazor 组件替换 MVC 页面上的所有 javascript,您可以尝试这个过程,它对我有用。
首先,将您的 MVC 项目更新或转换为 .Net 5.0.402。 它可能适用于早期版本,但我尚未对其进行测试。
向您的 MVC 解决方案添加一个 blazor Web 程序集应用程序项目。 这是 Web 程序集组件项目。
在 MVC 视图中,在您希望呈现 blazor 组件的位置添加:
@using myawesomewasmprojectnamespace.Pages
<component type="typeof(Counter)" render-mode="WebAssemblyPrerendered"/>
<script src="_framework/blazor.webassembly.js"></script>
“@using”声明指的是 blazor Web 程序集应用程序项目 Pages 目录。 “typeof(Counter)”类型是指 Visual Studio 提供的默认 blazor Web 程序集应用程序项目中的 Counter.razor 组件。
我假设您将能够编写自己的 blazor 组件以与 Counter.razor 组件交换。
在 MVC 项目的 _Layout.cshtml 中,或 MVC 视图的 <head>
标记所在的任何位置,在其中包含 blazor 组件的每个页面的 <head>
标记中包含:
<base href="/"/>
将“Microsoft.AspNetCore.Components.WebAssembly.Server”包添加到您的 MVC 项目中。
在 MVC 依赖项、项目引用中添加对 blazor Web 程序集应用程序项目的引用。
在 MVC 应用 Startup.cs, 'public void Configure(IApplicationBuilder app, IWebHostEnvironment env)' 方法中,添加以下内容:
app.UseBlazorFrameworkFiles();
在 blazor Web 程序集应用程序项目 Program.cs 文件中,注释掉以下行以停止应用程序寻找“<div id="app"></div>
”
//builder.RootComponents.Add<App>("#app");
最后,从 blazor Web 程序集应用程序项目的 wwwroot 目录中删除图标,因为它会与 MVC 冲突。
这会将“计数器”组件添加到您的 MVC 视图中。
要将不同的组件添加到不同的视图,请将其插入:
@using myawesomewasmprojectnamespace.Pages
<component type="typeof(Myawsomecomponentnamecompletelydifferentfromanymvccontrolleroractionname)" render-mode="WebAssemblyPrerendered"/>
<script src="_framework/blazor.webassembly.js"></script>
然后使用以下命令启动您的 blazor 组件:
@page "/myawsomecomponentnamecompletelydifferentfromanymvccontrolleroractionname"
这花了我很长时间才整理出来,如果它不适合你,请告诉我。
【讨论】:
您好,非常感谢您的回复。我能够在完全不同的框架之外运行 blazor 组件!我刚看到这个回复。 不用担心。如果不出意外,下次我忘记如何做时,我总是可以查找我的答案。不过我很想看看你的解决方案。 是的,我将我的解决方案添加为答案,然后您就可以完成它! :) 太棒了。我可能会使用它。我的答案现在给了我一大堆其他问题。 我添加了我的答案,请随意通过,上述工作流程对我们非常有效,我们很快就会上线。【参考方案2】:在做了大量研究并阅读了大量微软文档之后,我能够在不同的框架(在我的例子中是淘汰赛 mvc)中在 blazor 之外运行单独的 blazor 组件,
首先,我在 Visual Studio 中针对 .net 5.0 初始化了一个新的 Blazor Webassmebly 项目。
为简单起见,让我们从 blazor 引导应用程序中获取计数器组件。
步骤 - 1 将要导出的组件导入为可重用组件,如下所示 -
第 2 步 - 修改 MainLayout.razor 以加载组件
第 3 步 - 这是至关重要的一步。在您的 Counter 组件中,您应该添加以下代码行,这里我们将使用 DotNetObjectReference 设置组件的引用
注入
@inherits LayoutComponentBase @inject IJSRuntime js
在您的组件代码部分 -
private int currentCount = 0;
private DotNetObjectReference<Counter> jsToDotNetBridgeReference;
protected override async Task OnInitializedAsync()
jsToDotNetBridgeReference = DotNetObjectReference.Create(this);
await js.InvokeVoidAsync("SetDotNetReference", jsToDotNetBridgeReference);
[JSInvokable]
private void IncrementCount()
currentCount++;
[JSInvokable] 标识符帮助 dotnet 将此函数识别为从 JavaScript 调用的东西。
Step - 4 修改 Program.cs 和 index.html
修改您的 index.html 并将您的 div id 更改为 counter
接下来修改您的 program.cs 以在 html 中查找计数器 id。
第 5 步 - 将 dotnetreference 设置为 javascript 窗口对象
在 index.html 的 script 标签下添加以下脚本 -
window.SetDotNetReference = function (pDotNetReference)
DotNetReference = pDotNetReference;
这就是您在 blazor webassembly 应用程序上所要做的一切。
第 6 步 - 将您的 blazor 应用程序发布到文件夹。我现在使用默认位置。发布后,您将看到以下文件和文件夹,我们对 _framework 文件夹感兴趣。
发布完成后,将 _framework 文件夹复制到其他应用程序的根目录,如下所示 -
第 7 步 - 转到您想要的框架,现在我将使用淘汰赛 mvc 应用程序。
在您的 layout.cshtml 文件中添加对 blazor 库的引用,如下所示
<script src="~/_framework/blazor.webassembly.js" autostart="false"></script>
保留 autostart = false
是确保 Blazor 组件在不需要时不会加载的好方法。
第 8 步 - 创建 BlazorInterop.js
在您的框架项目中创建一个 js 文件,我喜欢将其命名为 BlazorInterop.js(可以是任何名称),然后在您的 layout.cshtml 中像这样引用它
<script src="~/BlazorInterop.js?" type="text/javascript"></script>
在 BlazorInterop.js 中,您将编写要从您的 blazor 应用程序中的主机应用程序执行的函数。像这样-
IncrementCounter = function ()
Blazor.start().then(()=>
DotNetReference.invokeMethodAsync('IncrementCounter');
)
第 9 步 - 在layput.cshtml 中使用id=counter
创建一个div
创建一个 id=counter 的 div,这将有助于 blazor appp 识别它应该像这样种植组件的 div -
<div id="counter">
</div>
<button type="button" onClick="IncrementCounter"> Increment Counter </button>
为了从页面加载时立即查看 blazor 组件,设置 autostart=true
否则,如果您想按需加载组件,我在主机应用程序中添加了一个按钮,以表明您可以根据需要调用 blazor 函数一旦组件被加载。
在您的 blazor interop.js 中,Blazor.start 将启动 blazor 应用程序,然后 DotNetReference.invokeMethodAsync
将触发 blazor 内的函数,并且计数器应递增。
第 10 步 - 在 web.config 中的 mvc 应用程序中添加 mime 类型,以便像这样提供静态内容 -
<staticContent>
<remove fileExtension=".wasm"/>
<mimeMap fileExtension=".wasm" mimeType="application/wasm"/>
<remove fileExtension=".dat"/>
<mimeMap fileExtension=".dat" mimeType="application/dat"/>
<remove fileExtension=".br"/>
<mimeMap fileExtension=".br" mimeType="application/br"/>
<remove fileExtension=".gz"/>
<mimeMap fileExtension=".gz" mimeType="application/gz"/>
<remove fileExtension=".blat"/>
<mimeMap fileExtension=".blat" mimeType="application/blat"/>
<remove fileExtension=".pdb"/>
<mimeMap fileExtension=".pdb" mimeType="application/pdb"/>
<remove fileExtension=".dll"/>
<mimeMap fileExtension=".dll" mimeType="application/octet-stream"/>
<remove fileExtension=".json"/>
<mimeMap fileExtension=".json" mimeType="application/json"/>
</staticContent>
完成了! 启动您的淘汰赛应用程序,您将能够看到该组件。
这基本上是我们在 mvc 淘汰应用程序中加载 blazor 组件所需发生的事情,这种方法也应该适用于任何其他框架,但是我不确定是否添加 mime 类型以在诸如 angulr 之类的框架中提供静态内容,反应等,但我相信一定有某种方式。我没有研究过。
可能会遇到一些错误,因此我将留下一些我在整个过程中提到的文档。
从 JS 调用 .Net 方法 https://docs.microsoft.com/en-us/aspnet/core/blazor/javascript-interoperability/call-dotnet-from-javascript?view=aspnetcore-6.0
从 .net 调用 JS 方法
https://docs.microsoft.com/en-us/aspnet/core/blazor/javascript-interoperability/call-javascript-from-dotnet?view=aspnetcore-6.0
如何正确使用 blazor.start
https://docs.microsoft.com/en-us/aspnet/core/blazor/fundamentals/startup?view=aspnetcore-6.0
我花了很多时间来整理,这个特定的工作流程对我们很有效,并计划在月底发布生产版本。
这有助于我们在 Blazor 中为我们的应用程序开发新功能,从而在无需获取新资源的情况下推进新技术。
【讨论】:
【参考方案3】:从 .NET 6 开始提供的一种可能性是通过调用 JSComponentConfigurationExtensions.RegisterForJavaScript
使 Blazor 组件可用于从 JavaScript 实例化。
我也处于想将现有 JS 应用程序逐步迁移到 Blazor 的情况。但是,它是一个 Angular 应用程序。为了评估可能的解决方案,我创建了一个演示迁移项目。有关代码和说明,请参阅我的 BlazorInAngularDemo github project 以及 working demo。但正如已经说过的,它专门针对 Angular。但也许一些想法,尤其是 README 文件中的一些想法,无论如何都可以帮助你。
【讨论】:
嗨,我能解决这个问题。我在这里发布了详细说明-medium.com/@kshitij.rangari92/…以上是关于在 blazor 应用程序之外使用 blazor 组件(例如,knockoutjs)的主要内容,如果未能解决你的问题,请参考以下文章
在 Blazor 组件之外设置 EventCallback<string>?