不是全文翻译,部分翻译自认为可能不准确,就原文照搬了。
创建一个Blazor TabControl组件,有两个目标知识点:
下面看最终效果图:

请先创建一个Blazor项目(Blazor Client或者Server皆可,我们以Blazor Server为例),
第一步,创建两个组件:TabControl和TabPage。TabPage组件有一个父TabControl属性引用(属性名Parent,添加CascadingParameter特性)。
TabControl组件:
文件路径:./Shared/TabControl.razor
<div>这是一个TabControl</div>
<CascadingValue Value="this">
@ChildContent
</CascadingValue>
@code {
// 如果我们想以<TabPage>标签的形式使用TabPage,那么下面的代码是必须的
[Parameter]
public RenderFragment? ChildContent { get; set; }
}
TabPage组件:
文件路径:./Shared/TabPage.razor
<div>这是一个TabPage</div>
@ChildContent
@code {
[CascadingParameter]
private TabControl? Parent { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
protected override void OnInitialized()
{
if (Parent == null)
throw new ArgumentNullException(nameof(Parent), "TabPage必须包含TabControl引用");
base.OnInitialized();
}
}
在TabPage的OnInitialized方法中添加下面这一行代码,使TabPage关联上TabControl:
Parent.AddPage(this);
AddPage方法见下面的代码,在TabControl调用AddPage方法保存引用后,我们在TabControl中添加ActivePage属性,同样看下面的代码:
public TabPage? ActivePage { get; set; }
readonly List<TabPage> _pages = new();
internal void AddPage(TabPage tabPage)
{
_pages.Add(tabPage);
if (_pages.Count == 1)
ActivePage = tabPage;
StateHasChanged();
}
给AddPage组件添加一个Text属性用于展示。
[Parameter]
public string? Text { get; set; }
在TabControl中添加以下标签(在ChildContent渲染之前),这些标签会一次性全部渲染出来,当点击某个TabPage时会改变TabControl的选择项。
<div class="btn-group" role="group">
@foreach (TabPage tabPage in Pages)
{
<button type="button"
class="btn @GetButtonClass(tabPage)"
@onclick=@( ()=>ActivatePage(tabPage) )>
@tabPage.Text
</button>
}
</div>
上面这些标签会创建标准的Bootstrap按钮组,每个TabPage会创建一个有以下特征的按钮:
GetButtonClass方法追加CSS类名,如果当前TabPage为ActivePage,添加CSS类btn-primary,否则添加btn-secondary。TabPage。注意:@onclick需要关联一个无参的方法,所以lambda表达式用一个内联的@( )来设置点击的TabPage为ActivatePage。
TabPage的Text属性设置。下面的代码添加到TabControl的代码区域。
string GetButtonClass(TabPage page)
{
return page == ActivePage ? "btn-primary" : "btn-secondary";
}
void ActivatePage(TabPage page)
{
ActivePage = page;
}
TabControl添加一个TabControlTest组件:
文件名:./Pages/TabControlTest.razor
@page "/tabcontroltest"
<TabControl>
<TabPage Text="Tab 1">
<h1>The first tab</h1>
</TabPage>
<TabPage Text="Tab 2">
<h1>The second tab</h1>
</TabPage>
<TabPage Text="Tab 3">
<h1>The third tab</h1>
</TabPage>
</TabControl>
@code {
}
在./Shared/NavMenu中添加TabControlTest路由
省略部分代码
<div class="nav-item px-3">
<NavLink class="nav-link" href="tabcontroltest">
<span class="oi oi-plus" aria-hidden="true"></span> TabControl Test
</NavLink>
</div>
省略部分代码
这样就完了吗?我们看看现在的效果:

不对吧,三个TabPage的内容全部显示出来了,解决这个问题只需要在TabPage渲染ChildContent时判断当前TabPage是否为TabControl选中的页,选中项才进行渲染:
@if (Parent.ActivePage == this)
{
@ChildContent
}
OK代码完,效果见本文开头。
原文作者:blazor university 原文链接:https://blazor-university.com/templating-components-with-renderfragements/creating-a-tabcontrol/ 文中代码已放:Github[1]
[1]Github: https://github.com/dotnet9/BlazorDemo