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

Angular自定义通知使用setTimeout的显示异常问题咨询

问题根因

你当前的实现中,每次触发新通知都会启动一个2秒后清空消息的定时器,但之前未执行完成的定时器不会被销毁,多个定时器叠加后会提前清空新推送的通知,就出现了闪现、显示时长不足的问题。

方案1:单通知覆盖模式(新通知替换旧通知,完整显示2秒)

该方案实现你要求的第一种效果:每次点击按钮先移除旧通知,新通知完整显示2秒,直到下一次点击触发新通知。仅需要修改组件TS文件,新增定时器清理逻辑即可:

import { tap } from 'rxjs/operators';
import { Observable } from 'rxjs';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  title = 'notification-messages';
  visible: boolean = true;
  // 新增变量存储定时器ID
  private notificationTimer: number | null = null;

  successMessage$: Observable<string> = this.notificationService.successMessageAction$.pipe(tap(_ => {
      // 每次收到新消息先清空之前未执行的定时器
      if (this.notificationTimer) {
        clearTimeout(this.notificationTimer);
      }
      this.notificationTimer = window.setTimeout(() => {
        this.notificationService.clearSuccessMessage();
        this.notificationTimer = null;
      }, 2000)
  })   
  );

  constructor(private notificationService: NotificationService) {}

  onClick() {
    this.notificationService.setSuccessMessage('Button clicked!');
  }
}
方案2:多通知堆叠模式(旧通知按时消失,新通知叠加展示)

该方案实现你要求的第二种效果:旧通知保持2秒显示时长,新通知叠加展示在旧通知上方,需要修改服务、组件TS和HTML三个文件:

修改NotificationService

改成存储消息队列,每个消息独立计时到期销毁:

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

// 定义通知消息结构
interface NotificationMessage {
  id: number;
  content: string;
}

@Injectable({
  providedIn: 'root'
})
export class NotificationService {
  // 用BehaviorSubject存储通知队列,初始为空数组
  private successMessagesSubject = new BehaviorSubject<NotificationMessage[]>([]);
  successMessages$ = this.successMessagesSubject.asObservable();

  setSuccessMessage(message: string) {
    const newMsg: NotificationMessage = {
      id: Date.now(), // 用时间戳作为唯一标识
      content: message
    };
    // 新消息追加到队列末尾
    const currentMsgs = this.successMessagesSubject.value;
    this.successMessagesSubject.next([...currentMsgs, newMsg]);

    // 独立给当前消息设置2秒后销毁的定时器
    setTimeout(() => {
      this.removeMessageById(newMsg.id);
    }, 2000);
  }

  private removeMessageById(id: number) {
    const currentMsgs = this.successMessagesSubject.value;
    const filteredMsgs = currentMsgs.filter(msg => msg.id !== id);
    this.successMessagesSubject.next(filteredMsgs);
  }
}

修改组件TS

调整接收的Observable为消息队列:

import { Component } from '@angular/core';
import { NotificationService } from './notification.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  title = 'notification-messages';
  visible: boolean = true;
  // 接收通知队列
  successMessages$ = this.notificationService.successMessages$;

  constructor(private notificationService: NotificationService) {}

  onClick() {
    this.notificationService.setSuccessMessage('Button clicked!');
  }
}

修改HTML模板

用*ngFor遍历消息队列渲染多个通知:

<div class="container">
  <div class="notifications">
    <scale-notification-message 
      variant="success" 
      opened
      @fadeAnimation
      *ngFor="let msg of successMessages$ | async"
    >
      {{ msg.content }}
    </scale-notification-message>
  </div>

  <button 
    type="button" 
    class="btn" 
    (click)="onClick()"
  >
    Click
  </button>
</div>

如果需要堆叠显示的样式优化,可以给.notifications容器添加以下CSS:

.notifications {
  position: fixed;
  top: 20px;
  right: 20px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 10:06:04