我们可以在常规的非 Blazor HTML 页面中将 Blazor 组件用作 Web 组件吗?
Posted
技术标签:
【中文标题】我们可以在常规的非 Blazor HTML 页面中将 Blazor 组件用作 Web 组件吗?【英文标题】:Can we consume a Blazor component as a Web Component within a regular non-Blazor HTML page? 【发布时间】:2021-08-23 08:54:44 【问题描述】:我们能否将 Blazor 组件呈现为独立的 DOM 片段,或者以其他方式将其作为标准 Web 组件在普通 html/JS 页面中使用?
从 Blazor 架构的角度来看,这可能是一个幼稚的问题。到目前为止,我还不是 Blazor 专家,但我认为它对于遗留 Web 应用程序的增量“棕地”现代化可能是一种有用的技术。我很惊讶这似乎没有得到官方支持。
为了说明,考虑这个简单的 Web 组件示例,它呈现一个自定义元素 <date-info>
:
// define a custom web component
customElements.define("date-info", class DateInfo extends HTMLElement
constructor()
super();
// create an "open" (vs "closed") shadow DOM,
// i.e., accessible to the outside javascript
this.attachShadow( mode: "open" );
async connectedCallback()
console.log(`$this.constructor.name.$this.connectedCallback.name called`);
// get the content from the server,
// this could be a Blazor component markup
try
const response = await fetch("https://worldtimeapi.org/api/ip");
const data = await response.json();
const content = new Date(data.utc_datetime).toString();
this.shadowRoot.innerHTML = `<span>$content</span>`;
catch(e)
console.error(e);
const info = document.createTextNode(e.message);
this.shadowRoot.appendChild(info);
);
<!-- use the web component -->
<p>Current time: <date-info/></p>
现在,我想获取并呈现 Blazor/Server 组件的分离标记,而不是获取 https://worldtimeapi.org/api/ip
,例如:
@* this is a Blazor component *@
<p>@(DateTime.Now)</p>
此外,我希望此标记保持功能性和动态性,即此 Blazor 组件的客户端 DOM 事件和服务器端更新,以通过包装 Web 组件的生命周期进一步传播两种方式.
当然可以将其设为 Blazor @page
并将其加载到 iframe
中,但我更希望将其呈现为外部页面 DOM 的一部分。
到目前为止,我遇到了这个:
显然,这不是 Blazor 早在 2018 年的设计目标之一: https://github.com/dotnet/aspnetcore/issues/16033.
后来 Steve Sanderson 创建了一个(非官方的)库来单独测试 Blazor 组件,理论上可以用来获取独立的 Blazor 组件标记:https://***.com/a/60457390/1768303。
到目前为止,这是解决这个问题的最佳方法吗?
【问题讨论】:
我不喜欢在同一个前端项目中混合技术。过去有太多不好的经历。很多事情都在 Blazor 的控制之下,特别是在使用 Signalr 更新 UI 的服务器端。我不记得您引用的库,但我认为它应该作为预渲染 HTML 集成工作,将组件的管理留在 Blazor 电路外部。查看chrissainty.com/…,了解现有 MVC 项目中的集成示例。 谢谢@NicolaBiada。我也不喜欢这种混合,但有些项目有非常具体的限制,所以这可能是一种进行增量更改的方式。您链接的文章很有用。也许,在部分 ASP.NET MVC 视图中使用Html.RenderComponentAsync
可以做到这一点。
是的,我使用相同的方法在身份服务器部分混合了 blazor 组件和 MVC 视图页面,仍然是 cshtml 格式。
@Webreaper,在 Twitter 上 Florian Rappl mentioned 他的项目 Piral 能够做到这一点。我认为:github.com/smapiot/Piral.Blazor
添加了一些代码的答案。相同的代码添加到github.com/dotnet/aspnetcore/issues/35551
【参考方案1】:
MS 已解决此限制,但该解决方案需要 .Net 6。
https://github.com/aspnet/AspLabs/tree/main/src/BlazorCustomElements
这是由史蒂夫·桑德森本人完成的。
【讨论】:
相关:github.com/dotnet/aspnetcore/issues/35372【参考方案2】:与此同时,您可以混合旧的 cshtml 与 razor 组件。 我使用这种方法在两个系统之间保持相同的图形布局。
一个例子,下面的文件是Identity使用的_Layout.cshtml。 我通过静态渲染使用了各种 Blazor 组件:
@using Microsoft.AspNetCore.Hosting
@using Microsoft.AspNetCore.Mvc.ViewEngines
@inject IWebHostEnvironment Environment
@inject ICompositeViewEngine Engine
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@using Project.Server.Shared
<!DOCTYPE html>
<html>
<head>
<component type="typeof(MainLayoutHead)" render-mode="Static" />
</head>
<body>
<app>
<div class="container main">
<component type="typeof(MainLayoutTopImages)" render-mode="Static" />
<div class="row navmenu-row">
<div class="col-md-12 bg-dark navmenu-col">
<component type="typeof(NavMenu)" render-mode="Static" />
</div>
</div>
<div class="row content pt-4 pb-0 mt-0">
<div class="col-md-12">
<div class="row">
<div class="col-md-12">
@*Required for GDPR.*@
<partial name="_CookieConsentPartial" />
</div>
</div>
<div class="row body-row">
<div class="col-md-12 body-col">
@RenderBody()
</div>
</div>
</div>
</div>
<component type="typeof(MainLayoutFooter)" render-mode="Static" />
</div>
</app>
<script src="~/Identity/lib/jquery/dist/jquery.min.js"></script>
<script src="~/Identity/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/Identity/js/site.js" asp-append-version="true"></script>
@RenderSection("Scripts", required: false)
</body>
</html>
MainLayoutHead
、MainLayoutFooter
和 NavMenu
是常规 Blazor 组件。
【讨论】:
这很棒。当您说“静态渲染”时,这是否意味着组件不是交互式的(即,您只是渲染样式化的静态组件,没有动态行为)?还是你指的是别的东西? (我的 MVC 生锈了,所以这里可能还有我不知道的意思)。 静态渲染意味着HTML将按原样渲染,第二阶段没有js或wasm突变。【参考方案3】:不确定这是否有帮助,但您绝对可以从服务器端页面执行此操作(如果没有,我将删除此答案)。这是一个测试页面,它在带有服务器端内容的 cshtml 页面中呈现所有三个标准“页面”。您实际上需要忘记 Blazor 中的“页面”概念。一切都是组件。页面只是具有Page
自定义属性的组件。
此设置的问题在于,一旦您刷新页面,您就会重新启动三个组件,并且您会丢失任何范围内的数据。
@page "/test"
@namespace ***.Answers.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@
Layout = null;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>***.Answers</title>
<base href="~/" />
<link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
<link href="css/site.css" rel="stylesheet" />
<link href="***.Answers.styles.css" rel="stylesheet" />
</head>
<body>
<div class="m-2 p-s bg-light">
<h3>A Normal Razor Page</h3>
<p>
Lots of server side rendered junk
</p>
<component type="typeof(***.Answers.Shared.SurveyPrompt)" render-mode="ServerPrerendered" />
</div>
<div class="m-2 p-s bg-info">
<h3>A Normal Header</h3>
<p>
Lots More server side rendered junk
</p>
<component type="typeof(***.Answers.Pages.Counter)" render-mode="ServerPrerendered" />
</div>
<div class="m-2 p-s bg-light">
<h3>A Normal Header</h3>
<p>
Lots More server side rendered junk
</p>
<component type="typeof(***.Answers.Pages.Counter)" render-mode="ServerPrerendered" />
</div>
<div class="m-2 p-s bg-light">
<h3>Yet Another Normal Header</h3>
<p>
Lots More server side rendered junk
</p>
<component type="typeof(***.Answers.Pages.FetchData)" render-mode="ServerPrerendered" />
</div>
<div class="m-2 p-s bg-light">
<h3>Yet Another Normal Header</h3>
<p>
Lots More server side rendered junk
</p>
<component type="typeof(***.Answers.Pages.FetchData)" render-mode="ServerPrerendered" />
</div>
<div id="blazor-error-ui">
<environment include="Staging,Production">
An error has occurred. This application may no longer respond until reloaded.
</environment>
<environment include="Development">
An unhandled exception has occurred. See browser dev tools for details.
</environment>
<a href="" class="reload">Reload</a>
<a class="dismiss">?</a>
</div>
<script src="_framework/blazor.server.js"></script>
</body>
</html>
【讨论】:
以上是关于我们可以在常规的非 Blazor HTML 页面中将 Blazor 组件用作 Web 组件吗?的主要内容,如果未能解决你的问题,请参考以下文章