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

Blazor 8中Razor页面时钟无法自动运行,如何解决?

Blazor SSR模式下时钟无法自动运行的解决方案

问题背景

在Blazor项目中已设置全局交互式服务器渲染模式,Clock Razor页面的时钟仅在手动刷新页面时正常显示,刷新后无法自动更新。已通过NuGet安装moment.js,尝试两种方案均未解决问题。

相关代码

Clock Razor页面

<h1>Current</h1>
<div id="clock"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js">
<script>
        function updateClock() {
            var now = moment().format('YYYY-MM-DD HH:mm:ss');
            document.getElementById('clock').innerText = now;
        }

        updateClock();

        setInterval(updateClock, 1000);
</script>

Program.cs 渲染模式配置

app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode();

尝试过的无效方案

方案一:通过IJSRuntime调用setInterval

[Inject]
private IJSRuntime JSRuntime { get; set; }

protected override async Task OnInitializedAsync()
{
    await JSRuntime.InvokeVoidAsync("setInterval");
}

方案二:添加额外程序集

app.MapRazorComponents<App>()
    .AddAdditionalAssemblies();

问题根源

  1. 原生<script>标签语法错误:第一个引入moment.js的script标签未闭合,导致后续JS代码无法正确解析执行。
  2. Blazor交互式服务器渲染模式下,组件内的原生JS代码执行时机与组件生命周期不匹配,组件初始化时DOM可能尚未就绪,JS逻辑无法绑定生效。
  3. 之前的方案逻辑错误:方案一未正确传递setInterval所需的参数;方案二的AddAdditionalAssemblies()未传入有效程序集,与JS执行无关。

解决步骤

1. 修复Script标签语法错误

确保引入moment.js的script标签正确闭合:

<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>

2. 使用JS隔离执行时钟逻辑

通过Blazor的JS隔离机制,在组件渲染完成后初始化时钟,确保DOM元素已存在:

步骤一:创建独立JS文件

在wwwroot/js目录下新建clock.js,封装时钟初始化逻辑:

export function initClock() {
    function updateClock() {
        const now = moment().format('YYYY-MM-DD HH:mm:ss');
        document.getElementById('clock').textContent = now;
    }
    // 初始化显示当前时间
    updateClock();
    // 设置每秒更新并返回定时器ID,用于销毁时清除
    return setInterval(updateClock, 1000);
}

export function stopClock(intervalId) {
    clearInterval(intervalId);
}

步骤二:修改Clock Razor组件

在组件中注入IJSRuntime,在OnAfterRenderAsync(组件渲染到DOM后触发)中调用JS函数,并实现销毁逻辑避免内存泄漏:

@inject IJSRuntime JSRuntime
@implements IAsyncDisposable

<h1>Current</h1>
<div id="clock"></div>

@code {
    private IJSObjectReference? _jsModule;
    private int? _intervalId;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            // 导入JS模块
            _jsModule = await JSRuntime.InvokeAsync<IJSObjectReference>(
                "import", "./js/clock.js");
            // 初始化时钟并保存定时器ID
            _intervalId = await _jsModule.InvokeAsync<int>("initClock");
        }
    }

    // 组件销毁时清除定时器
    public async ValueTask DisposeAsync()
    {
        if (_jsModule is not null && _intervalId.HasValue)
        {
            await _jsModule.InvokeVoidAsync("stopClock", _intervalId.Value);
            await _jsModule.DisposeAsync();
        }
    }
}

3. 确保moment.js全局可用

如果不想使用ES模块导入,可在项目的布局文件(如_Layout.cshtml或根组件的布局)中全局引入moment.js,确保JS代码能直接调用:

<!-- 在布局文件的<body>末尾添加 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>

为什么之前的方案无效?

  • 方案一:直接调用JSRuntime.InvokeVoidAsync("setInterval")未传入回调函数和间隔时间参数,不符合JSsetInterval的调用规范,无法触发时间更新逻辑。
  • 方案二:AddAdditionalAssemblies()用于添加包含Blazor组件的额外程序集,与JS代码执行无关,对时钟问题没有帮助。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 02:26:02