状态容器模式
我最终使用状态容器模式解决了这个问题。
如果您不知道那是什么,这些链接很有帮助:
https://chrissainty.com/3-ways-to-communicate-between-components-in-blazor/(最后一段)
https://www.youtube.com/watch?v=BB4lK2kfKf0&feature=youtu.be(通过其他选项进行更深入的潜水)
概述
我创建了一个 Scoped 服务来处理导航。它被注入到我的导航栏组件中,用于管理面包屑。导航服务还有一个事件,当面包屑更改时刷新导航栏 UI。
导航选项可以逐页配置。
为了方便我自己,我还创建了一个从 ComponentBase 继承的基本页面。
我已经稍微简化了我的代码。在我的实际项目中,我在这里管理的不仅仅是面包屑。
主布局
注意标题中的导航栏组件。
<header>
<Navbar />
</header>
<main>
@Body
</main>
导航栏组件
这使用 NavState 组件来构建我们的面包屑并处理可见性。本示例使用 mdbootstrap 4。在最后的代码块中,我们注册了 OnChange 事件,并使用它来重新渲染组件。我们还实现了 Dispose 以删除该事件绑定,否则我们可能会出现内存泄漏。
@inject NavState Nav
@implements IDisposable
<div class="subnav clearfix @(Nav.Visible ? "" : "invisible")">
@*BREADCRUMBS*@
<div class="float-left">
<ol class="breadcrumb">
@foreach (var item in Nav.Breadcrumbs)
{
if (item.Active)
{
<li class="breadcrumb-item active">@item.Text</li>
}
else
{
<li class="breadcrumb-item"><a href="@item.Link">@item.Text</a></li>
}
}
</ol>
</div>
</div>
@code {
protected override void OnInitialized()
{
Nav.OnChange += StateHasChanged;
}
public void Dispose()
{
Nav.OnChange -= StateHasChanged;
}
}
导航状态服务
作为范围服务注入。在服务器端 Blazor 中,范围服务存在于 Blazor 连接的整个生命周期中,因此我们必须小心在新页面加载时重置它。
另外值得注意的是:如果您打开多个选项卡,每个选项卡都有自己的连接,因此不会因为一个用户打开多个选项卡而导致损坏。
public class NavState : IScopedService
{
public List<Breadcrumb> Breadcrumbs { get; set; } = new List<Breadcrumb>();
public bool Visible { get; set; } = false;
public event Action OnChange;
public void SetVisible(bool isVisible)
{
Visible = isVisible;
NotifyStateChanged();
}
public void Reset()
{
Breadcrumbs = new List<Breadcrumb>();
Visible = false;
NotifyStateChanged();
}
public void SetBreadcrumbs(List<Breadcrumb> breadcrumbs)
{
Breadcrumbs = breadcrumbs;
Visible = true;
NotifyStateChanged();
}
private void NotifyStateChanged() => OnChange?.Invoke();
}
}
面包屑本身很简单:
public class Breadcrumb
{
public string Text { get; set; }
public string Link { get; set; }
public bool Active { get; set; }
}
基本页面
public class MyPageBase : ComponentBase
{
[Inject] protected NavState Nav { get; set; }
protected override void OnInitialized()
{
// NavState (breadcrumbs, etc) is Scoped, so it lives as long as our connection lives.
// So when a new page is visited, we need to clear navigation to prevent breadcrumbs from bleed-over, etc.
// This also makes the navbar invisible by default.
Nav.Reset();
}
}
页面
在您的页面上,如果您什么都不做,导航栏将是不可见的。或者您可以添加面包屑:
protected override async Task OnInitializedAsync()
{
...
Nav.SetBreadcrumbs(new List<Breadcrumb>()
{ new Breadcrumb(Text: "Test", Link: "https://google.com" }
);
...
}
在我的实际实现中,我还创建了一个流利的构建器,以使处理面包屑变得不那么笨拙,但我不想让人们不知所措。