【问题标题】:Scroll to specified part of page when clicking top navigation link in Blazor单击 Blazor 中的顶部导航链接时滚动到页面的指定部分
【发布时间】:2019-08-06 18:43:26
【问题描述】:

如何在 Blazor 中对已加载页面进行简单的“跳转”部分?像这样在 HTML 中:

<a href="#contact">Contact us</a>
...
<section id="contact">

理想情况下,我还希望它平滑地向下滚动到此部分。以为我会尝试用 CSS 解决这个问题,但也许不可能?

【问题讨论】:

标签: c# html css blazor


【解决方案1】:

您需要的是 Blazor 的散列路由功能。但是,唉,这样的功能还不存在。我建议您使用 JSIterop 来执行此任务:创建一个执行导航的 JavaScript,并将其传递给 ElementRef 对象。

希望对你有帮助……

编辑:以下是我在 Github 中找到的最佳解决方案的改编...

通常,当您单击联系链接时,您会被重定向到路由http://localhost:5000/mypage#contact,但会位于页面顶部。路由的片段不用于选择特定的 HTML 元素。

当前的解决方法是编写解释 URL 的显式代码。在上面的示例中,我们可以使用一点 JavaScript,然后从我们的 Blazor 代码中调用它:

mypage.cshtml:

         @page "/mypage"
    @inject Microsoft.AspNetCore.Components.Services.IUriHelper UriHelper

    <nav>

        <a href="#contact">contact</a>


    </nav>


    <section>
        <h2 id="contact">contact</h2>

    </section>


@functions {
    protected override void OnInit()
    {
        NavigateToElement();
        UriHelper.OnLocationChanged += OnLocationChanges;
    }

    private void OnLocationChanges(object sender, string location) => NavigateToElement();

    private void NavigateToElement()
    {
        var url = UriHelper.GetAbsoluteUri();
        var fragment = new Uri(url).Fragment;

        if(string.IsNullOrEmpty(fragment))
        {
            return;
        }

        var elementId = fragment.StartsWith("#") ? fragment.Substring(1) : fragment;

        if(string.IsNullOrEmpty(elementId))
        {
            return;
        }

        ScrollToElementId(elementId);
    }

    private static bool ScrollToElementId(string elementId)
    {
        return JSRuntime.Current.InvokeAsync<bool>("scrollToElementId", elementId).GetAwaiter().GetResult();
    }
}

index.html:

<script>
        window.scrollToElementId = (elementId) => {
            console.info('scrolling to element', elementId);
            var element = document.getElementById(elementId);
            if(!element)
            {
                console.warn('element was not found', elementId);
                return false;
            }
            element.scrollIntoView();
            return true;
        }
</script>

注意:如果您使用的是 Blazor 版本 .9.0,则应注入 IJSRuntime 请让我知道此解决方案是否适合您...

【讨论】:

  • 不错的 Issac,记住 JSRuntime.Current 不再受支持。现在 ( >= 0.9.0 ) 你必须通过 DI 实例化 JSRuntime。 :)
  • 试过了。 Microsoft Edge 滚动到正确的区域,然后当我单击导航中的其他链接时没有反应。 Chrome 和 Firefox 根本不滚动,点击导航中的其他链接时也没有任何反应。真的很感谢你的努力!如果其他人尝试过会很好,所以我知道我的网站中是否有其他东西导致问题。请注意,我正在运行 Blazor 0.7.0
  • 我现在已经在 Blazor 0.9.0 中尝试过了。使用创建新 Blazor 项目时创建的默认项目。只是想看看我的网站中是否有什么奇怪的东西阻止了它的工作。也没有在那里工作。在您找到它的 github 页面中,我看到他评论了“建议的解决方法不起作用,因为浏览器崩溃并且仅用于说明。”所以我猜我们只需要等待。
【解决方案2】:

和Issac的回答一样,但是需要改一些代码。

我发现主要问题是您需要它是异步的。 @johajan

@inject IJSRuntime JSRuntime

...

@functions {
protected override async Task OnInitAsync()
{
    await base.OnInitAsync();
    //NavigateToElement();
    UriHelper.OnLocationChanged += OnLocationChanges;
}

private async Task OnLocationChanges(object sender, string location) => await NavigateToElement();

private async Task NavigateToElement()
{
    var url = UriHelper.GetAbsoluteUri();
    var fragment = new Uri(url).Fragment;

    if(string.IsNullOrEmpty(fragment))
    {
        return;
    }

    var elementId = fragment.StartsWith("#") ? fragment.Substring(1) : fragment;

    if(string.IsNullOrEmpty(elementId))
    {
        return;
    }

    await ScrollToElementId(elementId);
}

private Task<bool> ScrollToElementId(string elementId)
{
    return JSRuntime.InvokeAsync<bool>("scrollToElementId", elementId);
}

}

【讨论】:

    【解决方案3】:

    我通过使用button 然后在标记中编写一些内联Javascript 解决了这个问题。您可以将此推广到 Blazor 组件以获得奖励积分!

    <button type="button" onclick="document.getElementById('contact').scrollIntoView({behavior:'smooth'})">Contact us</button>
    ...
    <section id="contact">
    

    【讨论】:

    • 谢谢,这几乎为我解决了!请参阅我的解决方案以添加到此解决方案。
    • 我看不出与您的回答有何不同,但很高兴它让您走上了正轨
    【解决方案4】:

    我使用了 Arron Hudon 的答案,但仍然没有用。然而,在玩了之后,我意识到它不适用于锚元素:&lt;a id='star_wars'&gt;Place to jump to&lt;/a&gt;。显然 Blazor 和其他 spa 框架在跳转到同一页面上的时存在问题。为了解决这个问题,我不得不改用段落元素(部分也可以):&lt;p id='star_wars'&gt;Some paragraph&lt;p&gt;

    使用引导程序的示例:

    <button class="btn btn-link" onclick="document.getElementById('star_wars').scrollIntoView({behavior:'smooth'})">Star Wars</button>
    
    ... lots of other text
    
    <p id="star_wars">Star Wars is an American epic...</p>
    

    请注意,我使用 bootstrap 的 btn-link 类使按钮看起来像一个超链接。

    【讨论】:

      【解决方案5】:

      你可以使用 2 个 Nuget 包来解决这个问题:

      1. Scroll JSJsInterop Nuget 的一部分。这有很多功能,请参阅文档,但主要部分是 IScrollHandler,这是一个可注入服务。您可以使用demo app 进行尝试。可以看到scrollIntoView()等JS函数包裹,平滑滚动可用。使用 JS 滚动支持要简单得多...
      2. 第二个选项是在您拥有“#”的 URL 中使用“Parmalinks”。 Nuget 在这里可用。这是你要求的。基本上它使用&lt;a&gt; 标签,但您不必费心(注意即使是演示应用程序也有# URL)。还呈现带有可点击图标和导航/复制操作的“链接”组件。当前平滑滚动不可用,但可以请求。您可以通过demo app 试用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-06-19
        • 1970-01-01
        • 2012-09-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-07-17
        • 1970-01-01
        相关资源
        最近更新 更多