【问题标题】:Blazor modal dialog has not focusBlazor 模式对话框没有焦点
【发布时间】:2021-12-02 10:51:35
【问题描述】:

我在 Blazor 中有一个自定义对话框。它基本上工作正常,但有一些缺陷:

  1. 当使用键盘焦点在底层页面上的控件之间而不是对话框内部跳转时。
  2. 在键盘上单击 Esc 或 Enter 时不会触发 keydown 事件。

缺少什么?


<div class="custom-modal-overlay fade @showClass" style="@style" aria-modal="@Show" aria-hidden="@(!Show)" aria-labelledby="Dialog" @onclick="HandleCancel" @onkeydown="OverlayKeyDown">
    <div class="custom-modal-dialog" @onclick:stopPropagation="true">
        <div class="custom-modal-header">
            <h1>@Title</h1>
            @if (!ShowCancel)
            {
                <div class="cancel-icon" @onclick="HandleCancel">
                    <span class="material-icons-outlined cancel-icon" role="img" aria-label="Cancel">clear</span>
                </div>
            }
        </div>
        <div class="custom-modal-content">
            @ChildContent
        </div>
        <div class="custom-modal-footer">
            @if (ShowCancel)
            {
                <button type="button" class="btn btn-sm btn-outline-secondary" @onclick="HandleCancel">Cancel</button>
            }
            <button type="submit" class="btn btn-sm btn-primary" @onclick="HandleConfirm">OK</button>
        </div>
    </div>

</div>

@code {

    [Parameter]
    public bool ShowCancel { get; set; } = true;


    [Parameter]
    public bool Show { get; set; }

    [Parameter]
    public EventCallback<bool> ShowChanged { get; set; }


    [Parameter]
    public string Title { get; set; }

    [Parameter]
    public RenderFragment ChildContent { get; set; }


    [Parameter]
    public EventCallback OnCancel { get; set; }

    [Parameter]
    public EventCallback OnConfirm { get; set; }



    private string showClass => Show ? "show" : string.Empty;
    private string style => Show ? "display: block;" : "display: none;";


    private void OverlayKeyDown(KeyboardEventArgs e)
    {
        // TODO: Detect what key is hit and take proper action
        var key = e.Key;

        Show = false;
        ShowChanged.InvokeAsync(Show);
        OnCancel.InvokeAsync();
        StateHasChanged();
    }

    private void HandleCancel()
    {
        Show = false;
        ShowChanged.InvokeAsync(Show);
        OnCancel.InvokeAsync();
    }

    private void HandleConfirm()
    {
        Show = false;
        ShowChanged.InvokeAsync(Show);
        OnConfirm.InvokeAsync();
    }
}

【问题讨论】:

  • 将 tabindex="-1" 添加到你有 onkeydown 的根元素。将 ref 指令添加到元素并调用 elementReference.FocusAsync()
  • 很好的答案!用 Enter 和 Esacpe 键解决了最重要的部分。但是 tabindex 仍然不起作用。

标签: modal-dialog blazor keyevent


【解决方案1】:

为了帮助未来的读者,我在此处添加了包含 Liero 建议更改的完整代码。请注意添加的 overlayElement 以及对 InvokeFocus 的建议调用需要在 OnAfterRender 事件处理程序中完成。

这解决了Enter 和Escape 的要求,但据我了解标签问题仍然相同。


<div class="custom-modal-overlay fade @showClass" style="@style" tabindex="-1" aria-modal="@Show" aria-hidden="@(!Show)" aria-labelledby="Dialog" @onclick="HandleCancel" @onkeydown="OverlayKeyDown" @ref="overlayElement">
    <div class="custom-modal-dialog" @onclick:stopPropagation="true">
        <div class="custom-modal-header">
            <h1>@Title</h1>
            @if (!ShowCancel)
            {
                <div class="cancel-icon" @onclick="HandleCancel">
                    <span class="material-icons-outlined cancel-icon" role="img" aria-label="Cancel">clear</span>
                </div>
            }
        </div>
        <div class="custom-modal-content">
            @ChildContent
        </div>
        <div class="custom-modal-footer">
            @if (ShowCancel)
            {
                <button type="button" class="btn btn-sm btn-outline-secondary" @onclick="HandleCancel">Cancel</button>
            }
            <button type="submit" class="btn btn-sm btn-primary" @onclick="HandleConfirm">OK</button>
        </div>
    </div>

</div>

@code {

    [Parameter]
    public bool ShowCancel { get; set; } = true;


    [Parameter]
    public bool Show { get; set; }

    [Parameter]
    public EventCallback<bool> ShowChanged { get; set; }


    [Parameter]
    public string Title { get; set; }

    [Parameter]
    public RenderFragment ChildContent { get; set; }


    [Parameter]
    public EventCallback OnCancel { get; set; }

    [Parameter]
    public EventCallback OnConfirm { get; set; }


    private ElementReference overlayElement;
    private string showClass => Show ? "show" : string.Empty;
    private string style => Show ? "display: block;" : "display: none;";

    protected override void OnAfterRender(bool firstRender)
    {
        overlayElement.FocusAsync();
    }

    private void OverlayKeyDown(KeyboardEventArgs e)
    {
        switch (e.Key)
        {
            case "Escape":
                HandleCancel();
                break;
            case "Enter":
                HandleConfirm();
                break;
        }
    }

    private void HandleCancel()
    {
        Show = false;
        ShowChanged.InvokeAsync(Show);
        OnCancel.InvokeAsync();
    }

    private void HandleConfirm()
    {
        Show = false;
        ShowChanged.InvokeAsync(Show);
        OnConfirm.InvokeAsync();
    }
}

【讨论】:

  • 防止在模态框外跳格是一个有趣的问题。该解决方案通常涉及使用 JavaScript 来捕获用户输入。如果您滚动到此页面的底部,则会有示例代码和有关如何将选项卡限制为模式对话框的演示。见:developers.google.com/web/fundamentals/accessibility/focus/…
猜你喜欢
  • 2012-04-12
  • 1970-01-01
  • 1970-01-01
  • 2021-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-29
  • 1970-01-01
相关资源
最近更新 更多