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

Blazor独立WASM(.NET8)迁移至Fluent UI:窗口尺寸监听方案咨询

在Fluent UI Blazor中监听浏览器窗口尺寸变化

一、Fluent UI Blazor的内置支持情况

Fluent UI Blazor没有提供和MudBlazor IBrowserViewportService完全对应的内置服务,但可以借助Blazor原生的JS互操作能力,轻松实现相同的窗口尺寸监听功能。

二、实现方案

方案1:封装可复用的Viewport监听服务

如果需要在多个组件中复用窗口监听逻辑,可以自己封装一个类似的服务:

  1. 定义服务接口和参数类
public interface IViewportService
{
    // 窗口尺寸变化时触发的事件
    event Func<ViewportEventArgs, Task> ViewportChanged;
    // 获取当前窗口尺寸
    Task<ViewportEventArgs> GetCurrentViewportAsync();
    // 开始监听
    void StartListening();
    // 停止监听
    void StopListening();
}

public class ViewportEventArgs
{
    public int Width { get; set; }
    public int Height { get; set; }
}
  1. 实现服务类
public class ViewportService : IViewportService, IAsyncDisposable
{
    private readonly IJSRuntime _jsRuntime;
    private DotNetObjectReference<ViewportService>? _dotNetRef;
    private bool _isListening;

    public event Func<ViewportEventArgs, Task>? ViewportChanged;

    public ViewportService(IJSRuntime jsRuntime)
    {
        _jsRuntime = jsRuntime;
    }

    public async Task<ViewportEventArgs> GetCurrentViewportAsync()
    {
        return await _jsRuntime.InvokeAsync<ViewportEventArgs>("viewport.getCurrentSize");
    }

    public void StartListening()
    {
        if (_isListening) return;

        _dotNetRef = DotNetObjectReference.Create(this);
        _jsRuntime.InvokeVoidAsync("viewport.startListening", _dotNetRef);
        _isListening = true;
    }

    public void StopListening()
    {
        if (!_isListening) return;

        _jsRuntime.InvokeVoidAsync("viewport.stopListening");
        _dotNetRef?.Dispose();
        _isListening = false;
    }

    [JSInvokable]
    public async Task OnViewportChanged(int width, int height)
    {
        ViewportChanged?.Invoke(new ViewportEventArgs { Width = width, Height = height });
    }

    public async ValueTask DisposeAsync()
    {
        StopListening();
        await Task.CompletedTask;
    }
}
  1. 编写JS逻辑(wwwroot/js/viewport.js)
window.viewport = {
    getCurrentSize: () => ({
        width: window.innerWidth,
        height: window.innerHeight
    }),
    startListening: (dotNetRef) => {
        const handler = () => {
            dotNetRef.invokeMethodAsync('OnViewportChanged', window.innerWidth, window.innerHeight);
        };
        window.addEventListener('resize', handler);
        window.viewport.resizeHandler = handler;
    },
    stopListening: () => {
        if (window.viewport.resizeHandler) {
            window.removeEventListener('resize', window.viewport.resizeHandler);
            delete window.viewport.resizeHandler;
        }
    }
};
  1. 注册服务并引入JS
    在Program.cs中添加服务注册:
builder.Services.AddScoped<IViewportService, ViewportService>();

在index.html中引入JS文件:

<script src="js/viewport.js"></script>
  1. 在组件中使用服务
@inject IViewportService ViewportService
@implements IAsyncDisposable

<div>当前窗口尺寸:@ViewportWidth × @ViewportHeight</div>

@code {
    private int ViewportWidth { get; set; }
    private int ViewportHeight { get; set; }

    protected override async Task OnInitializedAsync()
    {
        // 获取初始窗口尺寸
        var initialViewport = await ViewportService.GetCurrentViewportAsync();
        UpdateViewport(initialViewport);
        
        // 订阅尺寸变化事件并开始监听
        ViewportService.ViewportChanged += HandleViewportChange;
        ViewportService.StartListening();
    }

    private void UpdateViewport(ViewportEventArgs args)
    {
        ViewportWidth = args.Width;
        ViewportHeight = args.Height;
        // 在这里处理图片、覆盖层的缩放逻辑
    }

    private Task HandleViewportChange(ViewportEventArgs args)
    {
        UpdateViewport(args);
        StateHasChanged();
        return Task.CompletedTask;
    }

    public async ValueTask DisposeAsync()
    {
        ViewportService.ViewportChanged -= HandleViewportChange;
        ViewportService.StopListening();
        await Task.CompletedTask;
    }
}

方案2:组件内直接实现(无需封装服务)

如果只是单个组件需要监听,可以直接在组件内通过JS互操作实现:

@inject IJSRuntime JSRuntime
@implements IAsyncDisposable

<div>当前窗口尺寸:@Width × @Height</div>

@code {
    private int Width { get; set; }
    private int Height { get; set; }
    private DotNetObjectReference<YourComponentName>? _dotNetRef;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            _dotNetRef = DotNetObjectReference.Create(this);
            // 注册resize监听
            await JSRuntime.InvokeVoidAsync("addResizeListener", _dotNetRef);
            // 获取初始尺寸
            var size = await JSRuntime.InvokeAsync<(int width, int height)>("getWindowSize");
            Width = size.width;
            Height = size.height;
            StateHasChanged();
        }
    }

    [JSInvokable]
    public void OnWindowResize(int width, int height)
    {
        Width = width;
        Height = height;
        // 处理缩放逻辑
        StateHasChanged();
    }

    public async ValueTask DisposeAsync()
    {
        if (_dotNetRef != null)
        {
            await JSRuntime.InvokeVoidAsync("removeResizeListener");
            _dotNetRef.Dispose();
        }
    }
}

对应的JS代码(添加到index.html或单独JS文件):

let resizeHandler;

function getWindowSize() {
    return { width: window.innerWidth, height: window.innerHeight };
}

function addResizeListener(dotNetRef) {
    resizeHandler = () => {
        dotNetRef.invokeMethodAsync('OnWindowResize', window.innerWidth, window.innerHeight);
    };
    window.addEventListener('resize', resizeHandler);
}

function removeResizeListener() {
    if (resizeHandler) {
        window.removeEventListener('resize', resizeHandler);
        resizeHandler = null;
    }
}

三、性能优化建议

窗口resize事件会频繁触发,建议添加防抖逻辑减少回调执行次数,修改JS中的监听代码即可:

function addResizeListener(dotNetRef) {
    let timeoutId;
    resizeHandler = () => {
        clearTimeout(timeoutId);
        // 设置100ms延迟,可根据需求调整
        timeoutId = setTimeout(() => {
            dotNetRef.invokeMethodAsync('OnWindowResize', window.innerWidth, window.innerHeight);
        }, 100);
    };
    window.addEventListener('resize', resizeHandler);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 07:45:15