间隔函数会导致无限的 UI 负载,除非我在 URL 中输入“/index.html”

问题描述 投票:0回答:2

我正在尝试在我的 Angular 应用程序中制作一个简单的数字时钟,但目前我只是让它显示一个计数器,同时我弄清楚到底发生了什么:

在clock.component.html中:

<div class="time" id="time">{{ secondsPassed }}</div>

在clock.component.ts中:

@Component({
  selector: 'app-clock',
  standalone: true,
  imports: [],
  templateUrl: './clock.component.html',
  styleUrl: './clock.component.scss'
})
export class ClockComponent implements OnInit, OnDestroy {

  secondsPassed: number;
  timer: any;

  constructor() {
    this.secondsPassed = 0;
  }

  ngOnInit(): void {
    this.startTimer();
  }

  ngOnDestroy(): void {
    if (this.timer) {
      clearInterval(this.timer);
    }
  }

  startTimer() {
    this.timer = setInterval(() => {
      this.secondsPassed++;
      console.log(this.secondsPassed);
    }, 1000)
  }
}

每当我执行服务并继续 localhost:4200 时,它将永远卡在旋转的加载圈上,除非我手动输入 localhost:4200/index.html,此时它将正确显示计时器并更新。

我尝试了很多不同的东西,包括 rxjs 订阅和异步管道,但没有任何效果。我什至尝试在 Angular 区域之外运行,但计时器不会更新。

我注意到的一件非常奇怪的事情是,每当我保存对代码的更改并在 Angular 本地服务器运行时重建它时,它就会看起来好像有两个计时器在运行,所以我不确定 ngOnDestroy 是否被调用以及第一个还没清除?我对 Angular 还很陌生,所以我不知道这是否与我的问题有关。

感谢您的帮助!

html angular typescript setinterval angular17
2个回答
1
投票

出于某种原因,这个问题的答案有效。我不知道为什么,但至少它解决了我的问题:)


0
投票

我也遇到了同样的问题,花了很长时间才找到解决方案。

随着 Angular 17 中引入 SSR,页面的渲染发生在服务器上,从而产生包含初始页面状态的初始 HTML 内容。这会导致在计时器或间隔运行时渲染无法完成。

这可以通过

afterNextRender
方法来解决,该方法必须在可注入上下文中调用,最好是在
constructor
中调用。

afterNextRender(() => {
  setInterval(() => {
    console.log('Interval triggered');
    // Put your code here
    ngZone.run(() => {
      // Put your ui changes here
    });
  }, 10000);
}, {phase: AfterRenderPhase.Write});

UI 更改必须再次在 Angular 环境中进行。

确保使用正确的

RenderPhase

您问题的完整组成部分:

import {afterNextRender, AfterRenderPhase, Component, NgZone, OnDestroy, OnInit} from "@angular/core";

@Component({
  selector: 'app-clock',
  standalone: true,
  imports: [],
  templateUrl: './clock.component.html',
  styleUrl: './clock.component.scss'
})
export class ClockComponent implements OnInit, OnDestroy {

  secondsPassed: number;
  timer: any;

  constructor(private ngZone: NgZone) {
    this.secondsPassed = 0;
    afterNextRender(() => {
      this.startTimer();
    }, {phase: AfterRenderPhase.Write});
  }

  ngOnInit(): void {
    //this.startTimer();
  }

  ngOnDestroy(): void {
    if (this.timer) {
      clearInterval(this.timer);
    }
  }

  startTimer() {
    this.timer = setInterval(() => {
      this.ngZone.run(() => {
        this.secondsPassed++;
      });
      console.log(this.secondsPassed);
    }, 1000)
  }
}
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.