更改 Blazor 菜单中导航项的可见性

Posted

技术标签:

【中文标题】更改 Blazor 菜单中导航项的可见性【英文标题】:Change visibility of nav item in blazor menu 【发布时间】:2020-04-25 00:13:39 【问题描述】:

我正在使用带有 .NET Core 3.0 的 Blazor。 当用户尚未登录时,我想在我的菜单中显示登录信息。当他登录时,登录导航项应该被隐藏。我该怎么做?

编辑: 我通过使用异步任务更改了 OnInitializedAsync 方法,但这不是问题。对于第一次加载,它可以正常工作。但是然后我进入登录页面,登录并通过 NavigationManager 导航到主页,菜单不会“刷新”。我该如何解决这个问题?

以下代码不起作用...

<div>
    <ul class="nav flex-column">
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
                <span class="oi oi-home" aria-hidden="true"></span> Home
            </NavLink>
        </li>
        @if (!_isLoggedIn)
        
            <li class="nav-item px-3">
                <NavLink class="nav-link" href="login">
                    <span class="oi oi-person" aria-hidden="true"></span> <LocalizedString Key="NavMenuLogin" />
                </NavLink>
            </li>
            <li class="nav-item px-3">
                <NavLink class="nav-link" href="licenseedit">
                    <span class="oi oi-spreadsheet" aria-hidden="true"></span> <LocalizedString Key="NavMenuRegistration" />
                </NavLink>
            </li>
        
    </ul>
</div>

@code

    private bool _isLoggedIn;

    protected override async Task OnInitializedAsync()
    
        await base.OnInitializedAsync();
        await TokenExistAsync();
    

    private async Task TokenExistAsync()
    
        var retVal = await Http.GetStringAsync("api/Login/ExistToken");
        _isLoggedIn = retVal == "yes";
    


【问题讨论】:

寻找“AuthorizeView"”。 我正在使用不同的/自己的授权,所以我不能使用 AuthorizeView。改变这一点太耗时了。 你真的 CSS 类“隐藏”和“可见”吗? async void 仅用于事件处理程序。在这里使用它是一个错误。这些方法不能等待。很可能在GetStringAsync 有机会开始 执行之前已经完成了渲染。将async Task 用于不返回任何内容的异步方法。 【参考方案1】:

我改了上面的代码,还是不行

我想我明白你想要什么......下面是实现它的代码,只要我是对的......你想刷新 NavMenu 组件的内容,它嵌入在 MainLayout 组件中,从登录页面,对吧?

您可以使用各种方法来实现这一点。以下解决方案基于 App State Pattern。

首先,我们必须创建一个可以从 NavMenu 组件和 Login 组件访问的服务类。这是课程:

public class AppState

    private bool _loggedIn;
    public event Action OnChange;
    public bool LoggedIn
    
        get  return _loggedIn; 
        set 
            if (_loggedIn != value)
            
                _loggedIn = value;
                NotifyStateChanged();
            
        
    

    private void NotifyStateChanged() => OnChange?.Invoke();

这个类定义了一个名为 OnChange 的事件委托,它应该封装刷新 NavMenu 的方法。当布尔属性 LoggedIn 的值更改时,将调用此委托。当用户登录时,LoggedIn 属性的值可能会在登录页面中更改,因此该委托的任何订阅者(在我们的示例中为 NavMenu)都会收到此通知。

登录页面

@inject AppState AppState 注意上面将 AppState 注入到登录页面。放在页面顶部

AppState.LoggedIn = true; 该代码应放在登录过程的末尾。这将启动 OnChange 委托的触发。

NavMenu 组件

@inject AppState AppState @implements IDisposable

*

protected override void OnInitialized()

    AppState.OnChange += StateHasChanged;


public void Dispose()

    AppState.OnChange -= StateHasChanged;

现在,每当您登录时,AppState 服务都会通知 NavMenu 组件重新渲染,以便登录链接不可见(未渲染)

启动类

services.AddSingleton<AppState>();

【讨论】:

我在我的网站上使用它,它运行良好。我的网站针对几个不同的数据库提供相同的页面,用户执行更改数据库的操作。我需要 NavMenu 链接来反映当前选择的数据库。但是,我需要做一个小改动,即注册服务范围。作为单身人士,每个用户都会得到最后一个用户选择的任何站点。感觉最初提出的问题也应该是这种情况?【参考方案2】:

你有

protected override async void OnInitialized()

做到这一点

protected override async Task OnInitializedAsync()

几乎总是避免async void。在这种情况下,您的应用程序可以在 TokenExistAsync() 完成之前运行更新 UI 的逻辑。 void 版本并不意味着异步使用,名称是指导方针。

此外,Blazor 还特别支持 hidden 和类似的开/关属性。您可以使用:

<li class="nav-item px-3" hidden="@hideLogin">

使用反向逻辑,您将需要(),如hidden=@(!showLogin) 并在您的代码块中:

bool hideLogin = false;

...

  // _loginVisibility = "hidden";
  hideLogin = true;

【讨论】:

菜单项保持不变。因此,虽然我现在已经登录,但会显示登录项。【参考方案3】:

我稍微修改了你的代码...使用 Task 而不是 void。 试试这个代码 sn-p 代替:

@code

private string _loginVisibility = "visible";

protected override async Task OnInitializedAsync()

    await TokenExistAsync();


private async Task TokenExistAsync()

    var retVal = await Http.GetStringAsync("api/Login/ExistToken");
    if (retVal == "yes")
    
        _loginVisibility = "hidden";
    



如果此更改不起作用,请检查您的 CSS 类

注意:我认为使用字符串值来隐藏或显示 li 元素是错误的。您不必隐藏 li 元素。它根本不应该被渲染。你可以像这样定义一个布尔变量:

public bool ShowLink get; set; = true;

如您所见,该属性设置为默认值 true,从而呈现 li 元素:

 @if ( ShowLink )
 
 <li class="nav-item px-3">
        <NavLink class="nav-link" href="login">
            <span class="oi oi-person" aria-hidden="true"></span> 
 Login
        </NavLink>
    </li>
 

并且在 TokenExistAsync 方法中,如果此方法返回“yes”,则应将其设置为 false。因此 li 元素不会被渲染。

【讨论】:

【参考方案4】:

我想我知道问题出在哪里。上面的代码很好,可以工作。可能的问题可能在登录页面中。在类似 navigationManager.NavigateTo("/client/home") 的情况下,NavMenu 代码不会命中。为此,您应该使用第二个参数:navigationManager.NavigateTo("/client/home", true); 我希望这会有所帮助。

【讨论】:

以上是关于更改 Blazor 菜单中导航项的可见性的主要内容,如果未能解决你的问题,请参考以下文章

在菜单项的可见性模式之间进行动画处理

安卓 11 |地图导航的包可见性更改

如何为 ListView 的 ContextActions 的 MenuItem 添加可见性绑定

媒体查询和jquery“.slideToggle()”会在调整大小时更改li元素的可见性

更改组件可见性时 Android Studio 空对象引用错误

UWP / C#基于NavView模式更改控件可见性