【问题标题】:Blazor scrolling to new sectionBlazor 滚动到新部分
【发布时间】:2020-11-18 16:11:44
【问题描述】:

我在 blazor 中有一个列表组件,它有一个可折叠的创建部分,我希望当您单击以显示创建部分时它​​将显示并滚动到创建部分。 我的问题是 StateHasChanged() 没有及时更新 UI,所以当 javascript 触发时,我们试图滚动到的元素还不存在。

显然我可以通过超时来解决这个问题,但是在 Blazor 中执行此操作的更简洁的方法是什么?有没有办法说类似await StateUpdated()....

我的代码如下所示:

@page "/createlist"

<div>
    <h3>My List</h3>
    <a @onclick="ToggleAdding">
       Create New
    </a>
</div>

<ul>
    @* list existing items... *@
</ul>

@if (IsAdding)
{
    <div id="some-create-id">
        <h3>Add Section</h3>
        @* create controls here *@
    </div>
}

@code {

    public void ToggleAdding()
    {
        IsAdding = !IsAdding;

        // Need something similar to StateHasChanged(), that is awaitable.

        JsRuntime.InvokeVoidAsync("ScrollIn", new object[] { CreateElementId });
    }
}

而js很简单:

ScrollIn = id => {
    let element = document.getElementById(id);
    console.log(!!element ? "SCROLLIN" : "NO FOUND ELE", id);
    if (!!element) { element.scrollIntoView(); }
}

【问题讨论】:

  • 我在使用 scrollIntoView 的 UL/LI 方面有完全相同的体验,唯一的区别是我正在调用 Web 服务来显示要显示的项目。这对我来说似乎是框架中的一个错误,因为我什至尝试像这样链接异步任务:await Task.Run(UpdateMessages).ContinueWith(antecedent => ScrollIntoView());让它滚动的唯一方法是将 Task.Delay(500) 添加到 ScrollIntoView 方法。

标签: c# .net blazor blazor-server-side


【解决方案1】:

您需要从 OnAfterRender(Async) 进行 JavaScript 调用。详情请见ASP.NET Core Razor component lifecycle

我实际上会将 JavaScript 简化为:

ScrollElementIntoView = element => element.scrollIntoView();

然后 C# 代码将是这样的,不使用任何硬编码的 id:

@page "/scroll-test"
@inject IJSRuntime JsRuntime

<div>
    <h3>My List</h3>
    <a @onclick="ToggleAdding">
        Create New
    </a>
</div>

<ul>
    @foreach (var x in Enumerable.Range(0, 100)) {
        <li>@x</li>
    }
</ul>

@if (IsAdding)
{
    <div @ref="AddSectionRef">
        <h3>Add Section</h3>
    </div>
}

@code {
    bool IsAdding { get; set; }
    ElementReference AddSectionRef { get; set; }
    List<Func<Task>> AfterRenderAsyncJobs = new();

    private void ToggleAdding() {
        IsAdding = !IsAdding;
        AfterRenderAsyncJobs.Add(ScrollToAddSection);
        StateHasChanged();
    }

    private async Task ScrollToAddSection() {
        await JsRuntime.InvokeVoidAsync("ScrollElementIntoView", AddSectionRef);
    }

    protected override async Task OnAfterRenderAsync(bool firstRender) {
        while (AfterRenderAsyncJobs.Any()) {
            var job = AfterRenderAsyncJobs.First();
            AfterRenderAsyncJobs.Remove(job);
            await job.Invoke();
        }
    }
}

【讨论】:

  • 我目前无法轻松测试它,但听起来它会起作用,所以我会接受它作为答案。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-27
  • 2019-08-06
  • 2014-08-05
  • 2017-09-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多