【发布时间】:2021-02-20 04:27:52
【问题描述】:
我需要动态地将 Blazor 组件放入用户提供的内容中。本质上,该组件应该使用一些 UI 元素来扩展用户提供的标记。
假设用户提供了一些可以在其中包含“greeting-container”元素的内容,并且组件应该在该元素中插入一个问候按钮。
我当前的解决方案是调用 JavaScript 函数来移动 OnAfterRenderAsync 中的 DOM 元素(完整代码如下)。它似乎工作正常,但在 Blazor 中似乎不鼓励操作 DOM 元素,因为它会影响差异算法。所以我对此有几个问题:
- 像这样移动 DOM 元素有多糟糕?它是否会导致性能问题、功能问题或一些未定义的行为?
- 有没有更好的方法可以在不使用 JavaScript 的情况下实现相同的结果?我正在考虑为此使用
RenderTreeBuilder,但似乎它可能不是为此目的而设计的,因为建议使用硬编码的序列号,这在处理编译时未知的动态内容时似乎是不可能的。
当前解决方案代码:
Greeter.razor
@page "/greeter"
@inject IJSRuntime JSRuntime;
<div>
@((MarkupString)UserContentMarkup)
<div id="greeting">
<button @onclick="ToggleGreeting">Toggle greeting</button>
@if (isGreetingVisible) {
<p>Hello, @Name!</p>
}
</div>
</div>
@code {
[Parameter]
public string UserContentMarkup { get; set; }
[Parameter]
public string Name { get; set; }
private bool isGreetingVisible;
private void ToggleGreeting()
{
isGreetingVisible = !isGreetingVisible;
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await JSRuntime.InvokeVoidAsync("moveGreetingToContainer");
}
}
_Host.cshtml
window.moveGreetingToContainer = () => {
var greeting = document.getElementById("greeting");
var container = document.getElementById("greeting-container");
container.appendChild(greeting);
}
UserContentTest.razor
@page "/userContentTest"
@inject IJSRuntime JSRuntime;
<h3>Testing user content</h3>
<Greeter UserContentMarkup=@userContentMarkup Name="John"></Greeter>
@code {
private string userContentMarkup = "Some <b>HTML</b> text followed by greeting <div id='greeting-container'></div> and <i>more</i> text";
}
预期结果(点击“切换问候语”后):
<div>
Some <b>HTML</b> text followed by greeting
<div id="greeting-container">
<div id="greeting">
<button>Toggle greeting</button>
<p>Hello, John!</p>
</div>
</div> and <i>more</i> text
</div>
【问题讨论】:
标签: asp.net-core blazor blazor-server-side asp.net-blazor