如何从 blazor 页面修改布局?

Bri*_*Kay 5 c# blazor blazor-server-side asp.net-core-3.1

我正在尝试在 Blazor 中实现面包屑。似乎没有任何机制可以将数据上游传递到布局级别,所以我想知道人们是如何管理它的。

这是我的布局的简化版本:

<header>
    <Toolbar />
    <Breadcrumbs></Breadcrumbs>
</header>

<main class="mt-5">
     @Body
</main>
Run Code Online (Sandbox Code Playgroud)

这个想法是在任何给定的 Blazor 页面上,我希望能够设置面包屑。但是我的页面无法与布局或面包屑组件交互。

我考虑过/尝试过的事情:

  • 将我的布局包装在CascadingParameter 中,并在面包屑组件和我的页面中实现该参数。这不起作用,因为显然无法在子组件中更改级联值。
  • 一个巧妙的范围服务,可以同时实现页面和面包屑组件。但是对于“当前页面”级别没有范围界定,所以如果打开多个浏览器选项卡等,我担心奇怪的工件。在我写这篇文章时,我想到两个选项卡可能会产生两个电路,这是值得探索的东西,因为那是可行的。
  • 放弃并使用JS interop解决这个问题。这是核选项。这是可行的,只是跛脚。:) 必须有更好的方法,减少生命损失。

在这个古老的 GitHub 问题中,Steve Sanderson 回应了类似的需求,但他的解决方法是侵入性的。我希望现在有更好的东西:https : //github.com/dotnet/aspnetcore/issues/16009

这很有趣,但最终没有帮助:Blazor:从布局访问参数

Bri*_*Kay 4

状态容器模式

我最终使用状态容器模式解决了这个问题。

如果您不知道那是什么,这些链接会很有帮助:

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>
Run Code Online (Sandbox Code Playgroud)

导航栏组件

这使用 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

导航状态服务

作为范围服务注入。在服务器端 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

面包屑本身很简单:

    public class Breadcrumb 
    {
        public string Text { get; set; }
        public string Link { get; set; }
        public bool Active { get; set; }

    }
Run Code Online (Sandbox Code Playgroud)

基页

    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();
        }
    }
Run Code Online (Sandbox Code Playgroud)

页数

有了这些,在您的页面上,如果您什么都不做,导航栏将是不可见的。或者您可以添加面包屑:

        protected override async Task OnInitializedAsync()
        {
            ...

            Nav.SetBreadcrumbs(new List<Breadcrumb>() 
            { new Breadcrumb(Text: "Test", Link: "https://google.com" }
            );
            
            ...
        }
Run Code Online (Sandbox Code Playgroud)

在我的实际实现中,我还创建了一个流畅的构建器,以使面包屑的使用不再那么笨重,但我不想让人们不知所措。