Blazor 中的 ElementReference 如何工作?

How does ElementReference in Blazor work?

我正在构建一个根据输入进行过滤的下拉列表。当您单击向下箭头时,它应该聚焦于列表中的第一项。以下是我遇到的问题的简化版本。

当您在输入中输入“a”然后将其删除,然后按向下箭头时,我得到:字典中不存在给定的键。有人可以解释为什么会这样吗?为什么键不在字典中?是什么阻止了它被添加?

<div class="parent" >
<div class="container">
    <input class="input" @oninput="FilterIdentifiers" @onkeydown="(e) => HandleKBEvents(e)"/>
    <div class="dropdown">
        @{
            int i = 1;
            
            foreach (var identifier in identifiersUI)
            {
                <div class="dropdown-item" @key="identifier" tabindex="@i" @ref="refs[identifier]">@identifier</div>

                i++;
            }
        }


    </div>
</div>
@code {
private List<string> identifiers = new List<string>
{
    "Aaa",
    "Aab",
    "Aba",
    "Aca",
    "Baa",
    "Bba"
};

private List<string> identifiersUI = new List<string>();

private Dictionary<string, ElementReference> refs = new Dictionary<string, ElementReference>();

protected override async Task OnInitializedAsync()
{
    identifiersUI = identifiers;
}

private void FilterIdentifiers(ChangeEventArgs e)
{
    string input = e.Value.ToString();
    refs.Clear();
    identifiersUI = identifiers.Where(s => s.ToUpper().StartsWith(input.ToUpper())).ToList();
    
}

private void HandleKBEvents(KeyboardEventArgs e)
{
    if (e.Code == "ArrowDown")
    {
        refs[identifiersUI[0]].FocusAsync();

    }
}
}

当我将 FilterIdentifiers 方法更改为此时,它确实有效。我看到这个 GitHub Blazor @ref 并且我想我会尝试只删除被过滤掉的键以查看是否有任何不同......它确实有效。不太明白为什么...

private void FilterIdentifiers(ChangeEventArgs e)
{
    string input = e.Value.ToString();
    var id = identifiers.Where(s => s.ToUpper().StartsWith(input.ToUpper())).ToList();

    //remove removed elements from refs
    var elements = identifiersUI.Except(id);
    identifiersUI = id;

    foreach (var element in elements)
    {
        refs.Remove(element);
    }
}

我会说这是因为整个字典都被清除了。 而且我假设您希望 Blazor 每次重置 identifiersUI 列表时都“重新构建”该字典,同时循环它以重绘。

但 Blazor 的更改跟踪可能决定(并且理所当然地)这些元素没有改变并保持不变。它特别跟踪你的下拉项目,特别注意不要 fiddle 太多那些 identifier 没有改变的元素,因为你已经设置了 the @key attribute.

只需删除 refs.Clear() 并让 Blazor UI 管理 refs

private void FilterIdentifiers(ChangeEventArgs e)
{
   string input = e.Value.ToString();
   //refs.Clear();
identifiersUI = identifiers.Where(s => s.ToUpper().StartsWith(input.ToUpper())).ToList();
}

当您将 @ref 与 HTML 元素而不是 Component 对象一起使用时,幕后发生了很多事情。当您手动清除 refs 时,在下一个渲染事件中,Blazor 仍然认为它们在那里,因此不会再次添加它们。过滤掉 a 会删除第一个值,从而删除错误。如果放入断点,您会发现 refs 中只有两个元素,即 b。对 b 进行过滤,一切似乎都有效,但实际上 refs 中只有四个元素 - 只有 a 存在。