/** * 文件功能:聊天室特效管理器 * * 统一管理全屏 Canvas 特效的入口、防重入和资源清理。 * 使用方式:EffectManager.play('fireworks' | 'rain' | 'lightning' | 'snow' | 'sakura' | 'meteors' | 'gold-rain' | 'hearts' | 'confetti' | 'fireflies') */ const EffectManager = (() => { // 当前正在播放的特效名称(防止同时播放两个特效) let _current = null; // 全屏 Canvas 元素引用 let _canvas = null; // 待播放特效队列,避免多个进场效果互相打断 const _queue = []; /** * 获取或创建全屏 Canvas 元素 * 属性:fixed 定位,覆盖全屏,pointer-events:none 不阻止用户交互 */ function _getCanvas() { if (_canvas && document.body.contains(_canvas)) { return _canvas; } const c = document.createElement("canvas"); c.id = "effect-canvas"; c.style.cssText = [ "position:fixed", "top:0", "left:0", "width:100vw", "height:100vh", "z-index:99999", "pointer-events:none", ].join(";"); c.width = window.innerWidth; c.height = window.innerHeight; document.body.appendChild(c); _canvas = c; return c; } /** * 特效结束后清理 Canvas,重置状态,并停止音效 */ function _cleanup() { if (_canvas && document.body.contains(_canvas)) { document.body.removeChild(_canvas); } _canvas = null; _current = null; // 通知音效引擎停止(兜底:正常情况下音效会自行计时结束) if (typeof EffectSounds !== "undefined") { EffectSounds.stop(); } if (_queue.length > 0) { const nextType = _queue.shift(); if (nextType) { play(nextType); } } } /** * 播放指定特效 * * @param {string} type 特效类型:fireworks / rain / lightning / snow / sakura / meteors / gold-rain / hearts / confetti / fireflies */ function play(type) { // 防重入:同时只允许一个特效 if (_current) { console.log(`[EffectManager] 特效 ${_current} 正在播放,加入队列 ${type}`); _queue.push(type); return; } const canvas = _getCanvas(); _current = type; // 同步触发对应音效 if (typeof EffectSounds !== "undefined") { EffectSounds.play(type); } switch (type) { case "fireworks": if (typeof FireworksEffect !== "undefined") { FireworksEffect.start(canvas, _cleanup); } break; case "wedding-fireworks": // 婚礼专属:双倍礼花,粉金浪漫配色,持续 12 秒 if (typeof FireworksEffect !== "undefined") { FireworksEffect.startDouble(canvas, _cleanup); } break; case "rain": if (typeof RainEffect !== "undefined") { RainEffect.start(canvas, _cleanup); } break; case "lightning": if (typeof LightningEffect !== "undefined") { LightningEffect.start(canvas, _cleanup); } break; case "snow": if (typeof SnowEffect !== "undefined") { SnowEffect.start(canvas, _cleanup); } break; case "sakura": if (typeof SakuraEffect !== "undefined") { SakuraEffect.start(canvas, _cleanup); } break; case "meteors": if (typeof MeteorsEffect !== "undefined") { MeteorsEffect.start(canvas, _cleanup); } break; case "gold-rain": if (typeof GoldRainEffect !== "undefined") { GoldRainEffect.start(canvas, _cleanup); } break; case "hearts": if (typeof HeartsEffect !== "undefined") { HeartsEffect.start(canvas, _cleanup); } break; case "confetti": if (typeof ConfettiEffect !== "undefined") { ConfettiEffect.start(canvas, _cleanup); } break; case "fireflies": if (typeof FirefliesEffect !== "undefined") { FirefliesEffect.start(canvas, _cleanup); } break; default: console.warn(`[EffectManager] 未知特效类型:${type}`); _cleanup(); } } return { play }; })();