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

如何继承MudButton并扩展点击加载状态?求优化方案

MudButton加载状态扩展的实现优化建议

我已经实现了为MudButton添加点击加载状态的扩展逻辑,但不确定是否为最佳实践,希望得到优化建议。以下是我的实现代码:

实现代码

MudButtonLoading.razor

@inherits MudButton

<MudElement @bind-Ref="@_elementReference"
            HtmlTag="@HtmlTag"
            Class="@Classname"
            Style="@Style"
            @attributes="UserAttributes"
            @onclick="OnClickHandler"
            type="@ButtonType.ToDescriptionString()"
            href="@Href"
            target="@Target"
            rel="@GetRel()"
            disabled="@disabledState"
            ClickPropagation="@ClickPropagation">
    <span class="mud-button-label">
        @if (!string.IsNullOrWhiteSpace(StartIcon))
        {
            <span class="@StartIconClass">
                @if (!isProcessing)
                {
                    <MudIcon Icon="@StartIcon" Size="@(IconSize ?? Size)" Color="@IconColor" />
                }
                else
                {
                    <MudProgressCircular Class="ms-n1" Size="LoadingSize" Indeterminate="true" />
                }
            </span>
        }

        @if (isProcessing)
        {
            @if (string.IsNullOrWhiteSpace(StartIcon) && string.IsNullOrWhiteSpace(EndIcon))
            {
                <MudProgressCircular Class="ms-n1" Size="LoadingSize" Indeterminate="true" />
            }
        }
        @ChildContent
        @if (!string.IsNullOrWhiteSpace(EndIcon))
        {
            <span class="@EndIconClass">
                @if (!isProcessing)
                {
                    <MudIcon Icon="@EndIcon" Size="@(IconSize ?? Size)" Color="@IconColor" />
                }
                else
                {
                    <MudProgressCircular Class="ms-n1" Size="LoadingSize" Indeterminate="true" />
                }
            </span>
        }
    </span>
</MudElement>

MudButtonLoading.razor.cs

using Microsoft.AspNetCore.Components.Web;
using MudBlazor;

namespace Sample.Client.Components.Buttons
{
    public partial class MudButtonLoading
    {
        protected bool isProcessing;
        protected bool disabledState => base.GetDisabledState() || isProcessing;

        protected override async Task OnClickHandler(MouseEventArgs ev)
        {
            try
            {
                isProcessing = true;
                //StateHasChanged();
                //await Task.Delay(1);

                await base.OnClickHandler(ev);

            }
            finally
            {
                isProcessing = false;
            }
        }

        protected Size LoadingSize => IconSize ?? Size switch
        {
            Size.Small => Size.Small,
            var other => other - 1
        };
    }
}

优化建议

1. 支持外部双向控制加载状态

目前加载状态仅由按钮内部点击触发,实际场景中可能需要外部逻辑手动控制(比如表单校验后触发加载)。可以新增参数实现双向绑定:

[Parameter]
public bool IsProcessing { get; set; }

[Parameter]
public EventCallback<bool> IsProcessingChanged { get; set; }

// 替换原有的isProcessing字段,改为使用绑定参数
protected bool disabledState => base.GetDisabledState() || IsProcessing;

protected override async Task OnClickHandler(MouseEventArgs ev)
{
    try
    {
        if (!IsProcessing)
        {
            await IsProcessingChanged.InvokeAsync(true);
        }
        await base.OnClickHandler(ev);
    }
    finally
    {
        if (IsProcessing)
        {
            await IsProcessingChanged.InvokeAsync(false);
        }
    }
}

2. 提取重复渲染逻辑,减少代码冗余

StartIcon和EndIcon的加载状态渲染逻辑完全重复,可以提取为复用的RenderFragment:

@code {
    private RenderFragment RenderIconOrLoader(string icon, string iconClass) => __builder =>
    {
        if (!IsProcessing)
        {
            <span class="@iconClass">
                <MudIcon Icon="@icon" Size="@(IconSize ?? Size)" Color="@IconColor" />
            </span>
        }
        else
        {
            <span class="@iconClass">
                <MudProgressCircular Class="mud-margin-left-n1" Size="LoadingSize" Indeterminate="true" />
            </span>
        }
    };
}

// 在Razor模板中替换原有代码:
@if (!string.IsNullOrWhiteSpace(StartIcon))
{
    @RenderIconOrLoader(StartIcon, StartIconClass)
}

// 同理替换EndIcon部分

3. 确保加载状态UI及时更新

在设置IsProcessing=true后,若base.OnClickHandler执行过快,Blazor可能来不及更新UI。可以通过await Task.Yield()让UI线程优先渲染加载状态:

protected override async Task OnClickHandler(MouseEventArgs ev)
{
    try
    {
        await IsProcessingChanged.InvokeAsync(true);
        await Task.Yield(); // 让出UI线程,确保加载状态渲染完成
        await base.OnClickHandler(ev);
    }
    finally
    {
        await IsProcessingChanged.InvokeAsync(false);
    }
}

4. 增强可配置性,支持自定义加载内容

默认的进度环不一定满足所有场景,允许用户传入自定义加载内容会提升组件灵活性:

[Parameter]
public RenderFragment LoadingContent { get; set; }

// 在Razor模板中替换默认进度环:
@if (IsProcessing)
{
    @if (string.IsNullOrWhiteSpace(StartIcon) && string.IsNullOrWhiteSpace(EndIcon))
    {
        @(LoadingContent ?? (RenderFragment)(__builder => 
        {
            <MudProgressCircular Class="mud-margin-left-n1" Size="LoadingSize" Indeterminate="true" />
        }))
    }
}

5. 优化尺寸计算与样式一致性

LoadingSize的计算可以更贴合MudBlazor的尺寸规范,同时使用官方推荐的样式类名:

protected Size LoadingSize => IconSize ?? Size switch
{
    Size.Small => Size.Small,
    Size.Medium => Size.Small,
    Size.Large => Size.Medium,
    _ => Size.Small
};

// 将原有的ms-n1替换为官方类名mud-margin-left-n1,保持样式体系一致性

内容的提问来源于stack exchange,提问作者Bi Nguyễn

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 18:23:17