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

如何在MAUI Blazor中抽象封装加载指示器(Spinner)

Blazor 统一实现加载指示器的优雅方案

不用每个页面都写重复的加载逻辑,通过自定义基类+通用Spinner组件就能搞定,步骤如下:

1. 构建带加载状态的基类

创建一个继承自ComponentBase的基类,统一管理加载状态和异步操作的包裹逻辑,所有需要加载状态的页面/组件都继承这个基类:

public class LoadingComponentBase : ComponentBase
{
    protected bool IsLoading { get; private set; }

    protected async Task ExecuteWithLoading(Func<Task> action)
    {
        IsLoading = true;
        StateHasChanged(); // 强制触发UI更新,立刻显示加载状态

        try
        {
            await action();
        }
        finally
        {
            IsLoading = false;
            StateHasChanged();
        }
    }
}

这个基类里的ExecuteWithLoading方法会自动帮你处理加载状态的切换,不用手动写IsLoading = true/false。

2. 实现通用Spinner组件

写一个可复用的Spinner.razor组件,负责渲染加载动画和提示文本:

@if (IsVisible)
{
    <div class="spinner-overlay">
        <div class="spinner"></div>
        @if (!string.IsNullOrEmpty(Message))
        {
            <p class="spinner-message">@Message</p>
        }
    </div>
}

@code {
    [Parameter] public bool IsVisible { get; set; }
    [Parameter] public string Message { get; set; } = "加载中...";
}

再给组件加基础样式(可以放到全局CSS文件里):

.spinner-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(255,255,255,0.9);
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    z-index: 9999;
}

.spinner {
    border: 4px solid #e0e0e0;
    border-top-color: #2196f3;
    border-radius: 50%;
    width: 50px;
    height: 50px;
    animation: spin 1s linear infinite;
}

.spinner-message {
    margin-top: 16px;
    color: #666;
    font-size: 14px;
}

@keyframes spin {
    to { transform: rotate(360deg); }
}

3. 在页面/组件中使用

让你的页面或组件继承LoadingComponentBase,然后用ExecuteWithLoading包裹异步数据加载逻辑,最后根据IsLoading控制Spinner的显示:

@page "/user-list"
@inherits LoadingComponentBase

<Spinner IsVisible="@IsLoading" Message="正在加载用户列表..." />

@if (UserList != null)
{
    <div class="user-list">
        @foreach (var user in UserList)
        {
            <div class="user-item">@user.Name</div>
        }
    </div>
}

@code {
    private List<User> UserList { get; set; }

    protected override async Task OnInitializeAsync()
    {
        await ExecuteWithLoading(async () =>
        {
            // 实际项目里替换成真实的数据请求
            await Task.Delay(1500);
            UserList = await UserService.GetAllUsersAsync();
        });
    }
}

额外优化点

  • 如果需要处理加载失败的情况,可以在基类里增加IsError和ErrorMessage属性,在ExecuteWithLoading的catch块中设置状态,然后在页面里渲染错误提示。
  • 要是只想给组件局部加加载(不是全屏),可以修改Spinner的CSS,把position: fixed改成position: relative,并调整父容器的样式。
  • 可以给基类增加重载方法,支持带返回值的异步操作,比如ExecuteWithLoading<T>(Func<Task<T>> action),方便获取异步操作的返回结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 17:10:33