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

Blazor Server表单验证失败时用JS修改手风琴标题样式的问题

Blazor Server表单验证失败时修改手风琴标题样式问题

我开发的是Blazor Server应用,需求是:当表单验证失败(比如输入为空)时,将手风琴的标题改为红色。

当前代码

index.razor页面

@page "/"
<style>

</style>
<PageTitle>Blazor Bootstrap - Home</PageTitle>
<div class="test1">
    <EditForm Model="@registration" OnValidSubmit="HandleFormSubmission">
        <DataAnnotationsValidator />
        <Accordion>
            <AccordionItem Title="Accordion Item #1">
                <Content>
                    <InputText id="SmtpHost" @bind-Value="@registration.SmtpHost" placeholder="SMTP Host" />
                    <ValidationMessage For="@(() => registration.SmtpHost)" />
                </Content>
            </AccordionItem>
        </Accordion>
        <button type="submit">Submit</button>
    </EditForm>
</div>

@code {
    [Inject]
    protected IJSRuntime JSRuntime { get; set; }
    Data.Registration registration = new();
    bool isValidationError = false;
    bool isFormSubmitted = false;
    bool hasRendered = false;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
                // await Task.Yield();
                // await ToggleAccordionButtonError();
        }
    }

    public async Task HandleFormSubmission(EditContext context)
    {
        Console.WriteLine("Form Submitted Successfully");
        isValidationError = !context.Validate();

        Console.WriteLine("Testing");
        Console.WriteLine(isValidationError);

        if (isValidationError)
        {
            isFormSubmitted = true;
            if (hasRendered)
            {
                ToggleAccordionButtonError();
            }
            else
            {
                StateHasChanged(); // Notify Blazor to re-render the component
            }
        }
    }

    private async Task ToggleAccordionButtonError()
    {
        try
        {
            await JSRuntime.InvokeVoidAsync("toggleAccordionButtonError");
            await JSRuntime.InvokeVoidAsync("myJavaScriptFunction");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error invoking JavaScript function: {ex.Message}");
        }
    }
}

custom.js文件

console.log("File recognised");

function myJavaScriptFunction() {
    // Invoke an alert
    console.log("Hello from JavaScript!");
}

// .test1 .accordion-button
function toggleAccordionButtonError() {
    console.log("Hello from JavaScript!");
    var elements = document.querySelectorAll('.accordion-button.collapsed');
    elements.forEach(function (element) {
        element.style.backgroundColor = "red";
        element.style.color = "white";
    });
}

我确认custom.js能正常运行,但之前在HandleFormSubmission里调用JS互操作没效果,知道Blazor预渲染会限制JS调用时机,求可行的解决办法。


解决方案

方案一:用Blazor原生绑定(推荐,无需JS)

这种方式更符合Blazor组件化思想,还能避开预渲染的JS调用限制。

  1. 添加错误样式
    在index.razor的<style>标签里加入:
.accordion-button.error {
    background-color: red;
    color: white;
}
  1. 自定义手风琴标题模板
    如果使用的Blazor Bootstrap组件支持TitleTemplate(大部分新版本都支持),直接绑定样式类:
<AccordionItem>
    <TitleTemplate>
        <span class="@(isValidationError ? "error" : "")">Accordion Item #1</span>
    </TitleTemplate>
    <Content>
        <InputText id="SmtpHost" @bind-Value="@registration.SmtpHost" placeholder="SMTP Host" />
        <ValidationMessage For="@(() => registration.SmtpHost)" />
    </Content>
</AccordionItem>
  1. 简化表单提交逻辑
    去掉冗余的判断,验证失败后Blazor会自动触发组件更新:
public async Task HandleFormSubmission(EditContext context)
{
    isValidationError = !context.Validate();

    if (isValidationError)
    {
        isFormSubmitted = true;
        // 无需手动调用StateHasChanged,EditContext验证会自动触发重新渲染
    }
    else
    {
        Console.WriteLine("Form Submitted Successfully");
        // 验证通过后的业务逻辑
    }
}

方案二:修复JS互操作逻辑(如果必须用JS)

如果坚持要用JS,需要确保在组件渲染完成后再调用,避免预渲染的限制:

  1. 标记需要执行JS的状态
    在@code里添加一个标记变量:
bool needToggleError = false;
  1. 修改表单提交逻辑
public async Task HandleFormSubmission(EditContext context)
{
    isValidationError = !context.Validate();

    if (isValidationError)
    {
        isFormSubmitted = true;
        needToggleError = true;
        StateHasChanged(); // 触发组件重新渲染,之后OnAfterRenderAsync会执行
    }
    else
    {
        Console.WriteLine("Form Submitted Successfully");
    }
}
  1. 在OnAfterRenderAsync里执行JS
protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (needToggleError)
    {
        await ToggleAccordionButtonError();
        needToggleError = false; // 重置标记,防止重复执行
    }
}
  1. 修正JS选择器
    原选择器只选中折叠状态的手风琴按钮,改成选中所有目标按钮:
function toggleAccordionButtonError() {
    console.log("Hello from JavaScript!");
    var elements = document.querySelectorAll('.test1 .accordion-button');
    elements.forEach(function (element) {
        element.style.backgroundColor = "red";
        element.style.color = "white";
    });
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 03:21:02