import { Injectable, ComponentRef, createComponent, ApplicationRef, Injector } from '@angular/core'; import { ToastComponent } from '../components/toast/toast.component'; import { ToastType, ToastOptions } from '../models/toast.types'; @Injectable({ providedIn: 'root' }) export class ToastService { private toasts: ComponentRef[] = []; private container: HTMLElement | null = null; constructor( private appRef: ApplicationRef, private injector: Injector ) {} private ensureContainer() { if (!this.container) { this.container = document.createElement('div'); this.container.className = 'toast-container'; // 添加一些内联样式 this.container.style.position = 'fixed'; this.container.style.top = '20px'; this.container.style.right = '20px'; this.container.style.zIndex = '9999'; this.container.style.display = 'flex'; this.container.style.flexDirection = 'column'; this.container.style.alignItems = 'flex-end'; document.body.appendChild(this.container); } } show(message: string, options?: ToastOptions) { this.ensureContainer(); const type = options?.type || 'info'; const duration = options?.duration || 3000; const toastRef = createComponent(ToastComponent, { environmentInjector: this.appRef.injector, elementInjector: this.injector }); // 设置输入属性(类型安全) toastRef.instance.message = message; toastRef.instance.type = type; // 添加到DOM this.container?.appendChild(toastRef.location.nativeElement); this.appRef.attachView(toastRef.hostView); // 存储引用 this.toasts.push(toastRef); // 自动移除 setTimeout(() => { this.removeToast(toastRef); }, duration); return toastRef; } success(message: string, options?: Omit) { return this.show(message, { ...options, type: 'success' }); } error(message: string, options?: Omit) { return this.show(message, { ...options, type: 'error' }); } info(message: string, options?: Omit) { return this.show(message, { ...options, type: 'info' }); } warning(message: string, options?: Omit) { return this.show(message, { ...options, type: 'warning' }); } private removeToast(toastRef: ComponentRef) { const index = this.toasts.indexOf(toastRef); if (index > -1) { this.toasts.splice(index, 1); this.appRef.detachView(toastRef.hostView); toastRef.destroy(); } } clearAll() { this.toasts.forEach(toastRef => { this.appRef.detachView(toastRef.hostView); toastRef.destroy(); }); this.toasts = []; } }