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
相关产品推荐
相关产品推荐

