Dotnet9

联系请关注微信公众号:Dotnet9

文章

Blazor创建TabControl组件

Blazor University 2021-12-06 22:01:36 Blazor 26
创建一个Blazor TabControl组件,有两个目标知识点

不是全文翻译,部分翻译自认为可能不准确,就原文照搬了。

创建一个Blazor TabControl组件,有两个目标知识点:

  1. Pass data into a RenderFragment to give it context.
  2. Use a CascadingParameter to pass the parent TabControl component into its child TabPage components.

下面看最终效果图:

实操开始:

请先创建一个Blazor项目(Blazor Client或者Server皆可,我们以Blazor Server为例),

第一步,创建两个组件:TabControlTabPageTabPage组件有一个父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();
    }
}

TabControl关联TabPage

TabPageOnInitialized方法中添加下面这一行代码,使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会创建一个有以下特征的按钮:

  1. CSS类设置为"btn",并通过GetButtonClass方法追加CSS类名,如果当前TabPageActivePage,添加CSS类btn-primary,否则添加btn-secondary
  2. 当点击按钮时会激活点击的TabPage

注意@onclick需要关联一个无参的方法,所以lambda表达式用一个内联的@( )来设置点击的TabPageActivatePage

  1. 按钮的文字通过TabPageText属性设置。

下面的代码添加到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代码完,效果见本文开头。

文中代码已放:Github

留言

回复