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

Blazor Server:OnInitialized方法触发两次导致动画重复渲染

Blazor Server组件OnInitialized触发两次的解决方案

Blazor Server默认启用预渲染机制:服务器先生成静态HTML发送给浏览器(预渲染阶段),待SignalR连接建立后,组件会再次初始化并接管DOM,因此OnInitialized会执行两次,导致CSS动画等逻辑重复触发。

以下是两种解决思路:

一、禁用预渲染

如果不需要预渲染带来的SEO和初始加载优势,可以直接关闭预渲染,让组件只初始化一次。

1. 全局禁用(Program.cs)

builder.Services.AddServerSideBlazor(options =>
{
    // 禁用全局预渲染
    options.DisablePrerendering = true;
});

2. 单个组件禁用(.NET 8+)

在目标组件中指定渲染模式,关闭预渲染:

@page "/example"
@rendermode InteractiveServer(prerender: false)

<h3>@title</h3>

@code {
    private string title;

    protected override void OnInitialized()
    {
        title = "Page is initialized";
        Console.WriteLine("OnInitialized is called");
        base.OnInitialized();
    }
}

二、检测预渲染状态,控制逻辑执行

若需要保留预渲染,可通过判断当前是否处于预渲染阶段,让动画等逻辑只在连接建立后执行。

方法1:通过IHttpContextAccessor判断

预渲染阶段存在HttpContext,连接建立后该对象为null。

  1. 先在Program.cs注册服务:
builder.Services.AddHttpContextAccessor();
  1. 在组件中注入并判断:
@page "/example"
@inject IHttpContextAccessor HttpContextAccessor

<h3>@title</h3>
<!-- 仅在非预渲染阶段显示带动画的元素 -->
@if (!IsPrerendering)
{
    <div class="animated-title">@title</div>
}

@code {
    private string title;
    // 判断是否处于预渲染阶段
    private bool IsPrerendering => HttpContextAccessor.HttpContext != null;

    protected override void OnInitialized()
    {
        title = "Page is initialized";
        
        if (!IsPrerendering)
        {
            Console.WriteLine("OnInitialized (连接建立后) 被调用");
            // 这里执行仅需运行一次的逻辑,比如初始化动画相关操作
        }
        else
        {
            Console.WriteLine("OnInitialized (预渲染阶段) 被调用");
        }
        
        base.OnInitialized();
    }
}

方法2:使用OnAfterRenderAsync

OnAfterRenderAsync在预渲染阶段不会执行,仅在SignalR连接建立、组件完成首次渲染后触发,适合处理动画这类依赖DOM的逻辑:

@page "/example"
@inject IJSRuntime JS

<h3 @ref="titleElementRef">@title</h3>

@code {
    private string title;
    private ElementReference titleElementRef;

    protected override void OnInitialized()
    {
        title = "Page is initialized";
        Console.WriteLine("OnInitialized is called");
        base.OnInitialized();
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            // 仅在连接建立后的首次渲染执行
            Console.WriteLine("OnAfterRenderAsync (首次渲染) 被调用");
            // 通过JSInterop触发动画,比如添加CSS类
            await JS.InvokeVoidAsync("addClass", titleElementRef, "animate-fade-in");
        }
        await base.OnAfterRenderAsync(firstRender);
    }
}

对应的JS代码(可放在wwwroot/js/app.js中):

window.addClass = (element, className) => {
    element.classList.add(className);
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 04:01:12