// ==================== 冷却控制器工厂 ==================== /** * 创建一个冷却控制器实例 * @param {HTMLButtonElement} buttonEl 需要禁用的按钮元素 * @param {HTMLElement} timerEl 用于显示倒计时/消息的元素 * @returns {Object} 控制器对象,包含 start, stop, setPrefix, setError 方法 */ function createCoolDown(buttonEl, timerEl) { let countdown = 0; // 当前剩余秒数 let interval = null; // 倒计时定时器 let prefix = ''; // 前缀文本(如耗时信息) let errorTimeout = null; // 错误消息恢复定时器 let isErrorMode = false; // 是否处于错误消息显示模式 // 更新显示内容(内部调用) function updateDisplay() { if (!timerEl) return; if (isErrorMode) return; // 错误消息期间不覆盖 if (countdown > 0) { timerEl.textContent = prefix ? `${prefix} ⏱️ 冷却 ${countdown}s` : `⏱️ 冷却 ${countdown}s`; } else { timerEl.textContent = prefix || ''; } } // 清除倒计时定时器并启用按钮 function clearTimer() { if (interval) { clearInterval(interval); interval = null; } if (buttonEl) buttonEl.disabled = false; } // 停止所有冷却行为(不清除前缀) function stop() { if (errorTimeout) { clearTimeout(errorTimeout); errorTimeout = null; } isErrorMode = false; clearTimer(); countdown = 0; if (timerEl) timerEl.textContent = prefix || ''; } // ✅ 开始倒计时(方案A:每次开始时强制清空残留信息) function start(seconds, customPrefix = '') { // 停止任何进行中的倒计时和错误消息 stop(); // ✅ 强制清空所有残留:清空 timer 显示、重置 prefix、退出错误模式 if (timerEl) { timerEl.textContent = ''; // 立即清空显示,避免残留 } prefix = ''; // 清空前缀 isErrorMode = false; // 退出错误模式 if (errorTimeout) { clearTimeout(errorTimeout); errorTimeout = null; } if (seconds <= 0) return; countdown = seconds; prefix = customPrefix; if (buttonEl) buttonEl.disabled = true; updateDisplay(); interval = setInterval(() => { if (countdown > 0) { countdown--; if (countdown <= 0) { // 倒计时结束:清空前缀,只保留冷却完成的状态 clearTimer(); countdown = 0; // ✅ 倒计时结束后清空前缀,避免残留 prefix = ''; if (timerEl) timerEl.textContent = ''; } else { updateDisplay(); } } else { clearTimer(); // ✅ 倒计时已归零时清空 prefix = ''; if (timerEl) timerEl.textContent = ''; } }, 1000); } // 更新前缀(例如请求耗时),不影响倒计时进度 function setPrefix(newPrefix) { prefix = newPrefix; if (!isErrorMode) { if (timerEl) { if (countdown > 0) { timerEl.textContent = prefix ? `${prefix} ⏱️ 冷却 ${countdown}s` : `⏱️ 冷却 ${countdown}s`; } else { timerEl.textContent = prefix || ''; } } } } // 显示临时错误消息,duration 毫秒后恢复倒计时显示(如果倒计时还在) function setError(msg, duration = 3000) { if (!timerEl) return; // 清除之前的恢复定时器 if (errorTimeout) clearTimeout(errorTimeout); isErrorMode = true; timerEl.textContent = msg; errorTimeout = setTimeout(() => { isErrorMode = false; errorTimeout = null; // 恢复显示倒计时或前缀 if (countdown > 0) { updateDisplay(); } else { // ✅ 错误恢复后如果没有倒计时,清空显示 timerEl.textContent = ''; prefix = ''; } }, duration); } return { start, stop, setPrefix, setError }; }