You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Blazor中获取滚动位置?非鼠标滚轮场景遇难题

解决方案

核心结论

Blazor的原生事件参数(包括EventArgs或衍生类)并未暴露DOM元素的滚动位置(如scrollTop、scrollLeft)这类细节,因为Blazor的事件模型是跨平台抽象,没有直接映射所有DOM API。因此必须借助JavaScript来获取滚动位置。

另外,@onwheel仅响应鼠标滚轮触发的滚动,无法覆盖拖拽滚动条、触摸滑动、键盘操作(PageUp/PageDown等)、编程式滚动等场景,@onscroll才是覆盖所有滚动行为的正确事件选择。


具体实现方法

方法1:在Blazor滚动事件中调用JS获取位置

通过IJSRuntime调用JS函数,直接获取目标元素的滚动数据:

第一步:添加JS工具函数

将以下代码放在项目的_Host.cshtml(或组件内的<script>标签)中:

window.getScrollPosition = (element) => {
    return {
        scrollTop: element.scrollTop,
        scrollLeft: element.scrollLeft,
        scrollHeight: element.scrollHeight,
        clientHeight: element.clientHeight
    };
};

第二步:修改Blazor组件代码

@inject IJSRuntime JsRuntime

<div @ref="scrollContainer" @onscroll="HandleScroll" class="p-4 border-2 border-gray-200 border-dashed rounded-lg dark:border-gray-700 chat-area responsive-chat-area">
    @ChatContent
</div>

@code {
    [Parameter]
    public RenderFragment ChatContent { get; set; }

    private ElementReference scrollContainer;

    private async Task HandleScroll()
    {
        var scrollData = await JsRuntime.InvokeAsync<ScrollData>("getScrollPosition", scrollContainer);
        // 这里处理滚动数据,比如打印或业务逻辑
        Console.WriteLine($"当前滚动高度:{scrollData.ScrollTop},内容总高度:{scrollData.ScrollHeight}");
    }

    // 定义模型接收JS返回的滚动数据
    public class ScrollData
    {
        public int ScrollTop { get; set; }
        public int ScrollLeft { get; set; }
        public int ScrollHeight { get; set; }
        public int ClientHeight { get; set; }
    }
}

方法2:JS主动监听滚动,回调Blazor方法

如果需要更实时的监听,或避免每次滚动都调用JS,可以让JS主动绑定滚动事件,再通过DotNet回调Blazor方法:

第一步:Blazor组件代码

@inject IJSRuntime JsRuntime
@implements IAsyncDisposable

<div @ref="scrollContainer" class="p-4 border-2 border-gray-200 border-dashed rounded-lg dark:border-gray-700 chat-area responsive-chat-area">
    @ChatContent
</div>

@code {
    [Parameter]
    public RenderFragment ChatContent { get; set; }

    private ElementReference scrollContainer;
    private DotNetObjectReference<YourComponentName>? dotNetRef;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            dotNetRef = DotNetObjectReference.Create(this);
            await JsRuntime.InvokeVoidAsync("setupScrollListener", scrollContainer, dotNetRef);
        }
    }

    [JSInvokable]
    public void OnScrollTriggered(int scrollTop, int scrollLeft, int scrollHeight, int clientHeight)
    {
        // 处理滚动逻辑
        Console.WriteLine($"滚动位置更新:{scrollTop}");
    }

    public async ValueTask DisposeAsync()
    {
        if (dotNetRef != null)
        {
            await JsRuntime.InvokeVoidAsync("removeScrollListener", scrollContainer);
            dotNetRef.Dispose();
        }
    }
}

第二步:添加JS监听逻辑

const scrollListenerMap = new Map();

window.setupScrollListener = (element, dotNetRef) => {
    const listener = () => {
        dotNetRef.invokeMethodAsync(
            'OnScrollTriggered',
            element.scrollTop,
            element.scrollLeft,
            element.scrollHeight,
            element.clientHeight
        );
    };
    element.addEventListener('scroll', listener);
    scrollListenerMap.set(element, listener);
};

window.removeScrollListener = (element) => {
    const listener = scrollListenerMap.get(element);
    if (listener) {
        element.removeEventListener('scroll', listener);
        scrollListenerMap.delete(element);
    }
};

注意事项

  • 使用ElementReference绑定目标元素,避免通过类名/ID查找,防止Blazor组件重新渲染导致元素引用失效。
  • 方法2中必须实现IAsyncDisposable接口,在组件销毁时移除滚动监听,避免内存泄漏。

内容的提问来源于stack exchange,提问作者Regestea

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 11:03:24