js重新加载div_为Blazor添加一个全局加载指示器

本文介绍了如何在.NET5和Blazor应用中实现一个全局的加载指示器,包括针对WebAssembly首次加载和HTTP请求的处理。通过修改index.html,引入Bootstrap5的Spinner样式,结合JavaScript和C#代码,实现在HTTP请求开始时显示加载指示器,结束时隐藏。此外,还展示了如何使用HttpClientFactory和自定义处理程序来自动化这个过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

到目前为止,.NET 5已经出来了,Blazor也迎来了重大更新,之后的学习就要基于最新的.NET 5了

这次主要基于Web Assembly实现一个全局的加载指示器,她主要应用于两种场景:

  1. 应用第一次加载
  2. HTTP请求

1. 应用加载

众所周知,Web Assembly体积比较大,因此第一次加载会比较耗时,默认的程序模板中,在index.html页面里面有这么一段:

<div id="app">Loading...div>

其实她就是一个简化版的加载指示器,她的作用就是在程序加载完之前在页面上显示文字"Loading",虽然功能有了,但是还是寒酸了一点。

1.1 准备

网上有很多加载指示器的样式代码,挑选自己喜欢的即可,我找了Bootstrap 5里面的Spinner

https://v5.getbootstrap.com/docs/5.0/components/spinners/#growing-spinner

Bootstrap 5.0目前还是alpha阶段

1.2 修改index.html

先贴代码:

<head>
    <link href="xxxxx/bootstrap.min.css" rel="stylesheet"/>
    <style>#globalLoadingSpinnerBg, #globalLoadingSpinner {display:none;
        }.loading #globalLoadingSpinnerBg {display:block;
        }.loading #globalLoadingSpinner {display: flex;
        }style>
head>

<body class="loading">
    <div id="globalLoadingSpinnerBg" class="modal-backdrop fade show">div>
    <div id="globalLoadingSpinner" class="modal fade show" role="dialog">
        <div class="text-center;" style="margin: auto;">
            <div class="spinner-grow text-primary" role="status">
                <span class="visually-hidden">Loading...span>
            div>
            <div class="spinner-grow text-secondary" role="status">
                <span class="visually-hidden">Loading...span>
            div>
            <div class="spinner-grow text-success" role="status">
                <span class="visually-hidden">Loading...span>
            div>
            <div class="spinner-grow text-danger" role="status">
                <span class="visually-hidden">Loading...span>
            div>
            <div class="spinner-grow text-warning" role="status">
                <span class="visually-hidden">Loading...span>
            div>
            <div class="spinner-grow text-info" role="status">
                <span class="visually-hidden">Loading...span>
            div>
            <div class="spinner-grow text-light" role="status">
                <span class="visually-hidden">Loading...span>
            div>
            <div class="spinner-grow text-dark" role="status">
                <span class="visually-hidden">Loading...span>
            div>
        div>
    div>

    <div id="app">div>
body>

要点:

  1. 引入Bootstrap的样式表
  2. 添加指示器的HTML代码,注意是作为body里面的第一个元素,这样才能保证在加载Blazor程序集之前显示。这里把指示器放入了模态对话框里面,目的是想在加载的时候阻止用户的其他操作,比如频繁的重复点击按钮等。
  3. 为body添加样式名“loading", 通过head里面的样式定义可以看到,当为body添加“loading”样式的时候,显示指示器,否则隐藏指示器。

这样只要页面开始加载的时候就会显示加载指示器。

1.3 隐藏指示器

如何隐藏指示器?

其实只要移除body里面的loading样式名就可以了,我们可以借助Js的互操作,通过javascript函数来实现。

function hideGlobalLoadingSpinner() {
    document.body.classList.remove('loading');
}

何时隐藏?

回顾一下Blazor的页面周期, 我们需要在页面组件全部加载完以后隐藏指示器,那么可以选择的有OnAfterRender,OnAfterRenderAsync。

由于App组件是整个Blazor的根组件,因此我们可以修改她的OnAfterRenderAsync,调用上面的JS函数:hideGlobalLoadingSpinner。

protected async override Task OnAfterRenderAsync(bool firstRender)
{
    await base.OnAfterRenderAsync(firstRender);
    await jsRuntime.InvokeVoidAsync("hideGlobalLoadingSpinner");
}

2. HTTP请求

Web Assembly应用离不开HTTP请求,那么如何在请求开始前显示加载指示,请求结束后隐藏呢?

显然不可能每个HTTP请求都写代码进行这些操作,幸运的是.NET Core提供了IHttpClientFactory,可以帮助我们在请求的上下文中嵌入自己的处理程序。

2.1 封装Javascript调用

前面已经有了隐藏指示器的Javascript函数,我们还需要一个函数来显示指示器, 很简单,为body添加loading样式名就行了:

function showGlobalLoadingSpinner() {
    document.body.classList.add('loading');
}

为了隐藏Javascript的调用细节,并方便在组件内使用,有必要封装成c#类。

先定义一个接口,包含显示和隐藏两个方法:

public interface IGlobalLoadingSpinner
{
    Task ShowAsync();
    Task HideAsync();
}

接下来看实现:

public class DefaultGlobalLoadingSpinner : IGlobalLoadingSpinner
{
    static object Locker = new object();
    int SpinnerCount = 1;

    IJSRuntime _jsRuntime;

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

    public async Task ShowAsync()
    {
        lock (Locker)
        {
            SpinnerCount++;
        }

        await this._jsRuntime.InvokeVoidAsync("showGlobalLoadingSpinner");
    }

    public async Task HideAsync()
    {
        lock (Locker)
        {
            SpinnerCount--;
            if (SpinnerCount 0)
            {
                SpinnerCount = 0;
            }
        }

        if (SpinnerCount == 0)
        {
            await this._jsRuntime.InvokeVoidAsync("hideGlobalLoadingSpinner");
        }
    }
}

要点:

  • 注入IJSRuntime,方便Javascript函数的调用。
  • 加入Locker以及SpinnerCount,这里的考虑是可能一次发起多个HTTP请求,可能会调用多次Show函数,因此我们使用计数器来记录请求数量的变化,当计数器变为0的时候才真正隐藏指示器。
  • SpinnerCount的初始值为什么是1?因为index.html刚加载的时候是默认显示指示器的。

如何使用该接口?

首先修改Program.cs,注入IGlobalLoadingSpinner

builder.Services.AddSingleton();

然后在组件内注入该接口,比如上面的App组件我们可以修改为

@inject IGlobalLoadingSpinner globalLoadingSpinnerprotected async override Task OnAfterRenderAsync(bool firstRender)
{
    await base.OnAfterRenderAsync(firstRender);
    await globalLoadingSpinner.HideAsync();
}

2.2 添加自定义HTTP处理程序

该处理程序用来在HTTP请求的上下文中显示和隐藏加载指示器:

public class LoadingSpinnerMessageHandler : DelegatingHandler
{
    private readonly ILogger _logger;private readonly IGlobalLoadingSpinner _loadingSpinnerService;public LoadingSpinnerMessageHandler(ILogger logger, IGlobalLoadingSpinner loadingSpinnerService)
    {
        _logger = logger;
        _loadingSpinnerService = loadingSpinnerService;
    }protected async override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {//发送请求之前显示加载指示器await _loadingSpinnerService.ShowAsync();//发送请求var response = await base.SendAsync(request, cancellationToken);//收到结果之后隐藏加载指示器await _loadingSpinnerService.HideAsync();return response;
    }
}

自定义处理程序继承自DelegatingHandler(来自命名空间System.Net.Http),主要实现了SendAsync方法,该方面里面使用前面定义的接口来显示和隐藏加载指示器。

2.3 使用HttpClient请求

Blazor里面的Http请求都需要用到HttpClient,这里我们利用HttpClientFactory来创建HttpClient了,首先还是修改Program.cs:

//注入前面创建的处理程序
builder.Services.AddTransient();//定义HttpClientFactory,并添加处理程序//这里使用了命名的HttpClient,当然你也可以定义所有HttpClient全部使用该处理程序//详情查看:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-5.0//需要先安装包Microsoft.Extensions.Http
builder.Services.AddHttpClient("sampleapi", client =>
{
    client.BaseAddress = new Uri("http://localhost:5000");
})
.AddHttpMessageHandler();

组件内使用也很简单:

@inject IHttpClientFactory httpFacprotected async Task LoadData()
{
    //通过名称创建HttpClient
    var httpClient = this.httpFac.CreateClient("sampleapi");
    //发送请求的时候,自动显示和隐藏加载指示器
    var forecasts = await httpClient.GetFromJsonAsync("WeatherForecast");
}

最终效果如下:

62b43f1c9355db404bca1cac45dd081f.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值