Blazor独立WASM(.NET8)迁移至Fluent UI:窗口尺寸监听方案咨询
在Fluent UI Blazor中监听浏览器窗口尺寸变化
一、Fluent UI Blazor的内置支持情况
Fluent UI Blazor没有提供和MudBlazor IBrowserViewportService完全对应的内置服务,但可以借助Blazor原生的JS互操作能力,轻松实现相同的窗口尺寸监听功能。
二、实现方案
方案1:封装可复用的Viewport监听服务
如果需要在多个组件中复用窗口监听逻辑,可以自己封装一个类似的服务:
- 定义服务接口和参数类
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; } }
- 实现服务类
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; } }
- 编写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; } } };
- 注册服务并引入JS
在Program.cs中添加服务注册:
builder.Services.AddScoped<IViewportService, ViewportService>();
在index.html中引入JS文件:
<script src="js/viewport.js"></script>
- 在组件中使用服务
@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
相关产品推荐
相关产品推荐

