Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder
提供了用于操作组件和元素的方法,包括在代码C#中手动生成组件。
备注
使用 RenderTreeBuilder
创建组件是一种高级方案。 格式不正确的组件(例如,未闭合的标记标记)可能会导致未定义的行为。
请考虑以下 PetDetails
组件,该组件可以手动内置到另一个组件中:
<h2>Pet Details Component</h2> <p>@PetDetailsQuote</p> @code { [Parameter] public string PetDetailsQuote { get; set; } }
在下面的示例中,CreateComponent
方法中的循环生成三个 PetDetails
组件。 当调用 RenderTreeBuilder
方法来创建组件(OpenComponent
和 AddAttribute
)时,序列号为源代码行号。 Blazor 差异算法依赖于与不同代码行对应的序列号,而不是不同的调用调用。 使用 RenderTreeBuilder
方法创建组件时,将序列号的参数硬编码。 使用计算或计数器生成序列号会导致性能不佳。 有关详细信息,请参阅 "序列号与代码行号和非执行顺序相关" 部分。
BuiltContent
组件:
@page "/BuiltContent" <h1>Build a component</h1> @CustomRender <button type="button" @onclick="RenderComponent"> Create three Pet Details components </button> @code { private RenderFragment CustomRender { get; set; } private RenderFragment CreateComponent() => builder => { for (var i = 0; i < 3; i++) { builder.OpenComponent(0, typeof(PetDetails)); builder.AddAttribute(1, "PetDetailsQuote", "Someone's best friend!"); builder.CloseComponent(); } }; private void RenderComponent() { CustomRender = CreateComponent(); } }
警告
Microsoft.AspNetCore.Components.RenderTree
中的类型允许处理呈现操作的结果。 这是 Blazor 框架实现的内部详细信息。 这些类型应被视为不稳定,并且在将来的版本中可能会更改。
Razor 组件文件(razor)始终被编译。 由于编译步骤可用于注入在运行时提高应用程序性能的信息,因此编译可能会与解释代码的优点相同。
这些改进的一个关键示例涉及序列号。 序列号指示运行时输出来自代码的不同和有序行。 运行时使用此信息以线性时间生成有效的树差异,其速度远快于一般树差异算法通常可以实现的速度。
请考虑以下 Razor 组件(razor)文件:
@if (someFlag) { <text>First</text> } Second
前面的代码编译为类似于下面的内容:
if (someFlag) { builder.AddContent(0, "First"); } builder.AddContent(1, "Second");
当第一次执行代码时,如果 true``someFlag
,生成器将接收:
序列 | 类型 | 数据 |
---|---|---|
0 | Text 节点 | First |
1 | Text 节点 | 秒 |
假设 someFlag
成为 false
,并再次呈现标记。 这次,生成器将接收:
序列 | 类型 | 数据 |
---|---|---|
1 | Text 节点 | 秒 |
当运行时执行差异时,它会发现序列 0
上的项已被删除,因此它生成以下简单的编辑脚本:
假设你编写了以下呈现树生成器逻辑:
var seq = 0; if (someFlag) { builder.AddContent(seq++, "First"); } builder.AddContent(seq++, "Second");
现在,第一个输出是:
序列 | 类型 | 数据 |
---|---|---|
0 | Text 节点 | First |
1 | Text 节点 | 秒 |
此结果与以前的情况相同,因此不存在负面问题。 第二个呈现 false
someFlag
,输出为:
序列 | 类型 | 数据 |
---|---|---|
0 | Text 节点 | 秒 |
这次,比较算法会发现两个更改已发生,并且算法将生成以下编辑脚本:
Second
。生成序列号会丢失有关原始代码中 if/else
分支和循环的位置的所有有用信息。 这会导致两次比较,就像以前一样。
这是一个简单的示例。 在具有复杂、深度嵌套结构的更真实的情况下,特别是在循环中,性能开销通常较高。 比较算法不必立即确定哪些循环块或分支已插入或删除,而是必须将其深度递归到呈现树中。 这通常会导致生成更长的编辑脚本,因为比较算法 misinformed 了旧结构与新结构之间的关系。
RenderTreeBuilder
逻辑。 首选razor文件,并允许编译器处理序列号。 如果无法避免手动 RenderTreeBuilder
逻辑,请将长代码块拆分为 OpenRegion
/CloseRegion
调用中的小块。 每个区域都有其自己单独的序列号空间,因此可以从每个区域内的零(或任何其他任意数字)重新启动。