class Debounce { constructor() { this.timers = new Map(); this.counters = new Map(); this.v3 = new Map(); } // 增加倒计时功能和连续点击触发功能 // key: 唯一键 // callback: 目标事件 // interrupt: 中断事件 // wait: 倒计时时间 // 执行防抖操作的方法 do(key, callback, wait = 300) { if (this.timers.has(key)) { clearTimeout(this.timers.get(key)); } const timer = setTimeout(() => { callback(); this.timers.delete(key); }, wait); this.timers.set(key, timer); } /** * * @param key * @param options * @param {number} [options.duration=10000] - 总倒计时时长(毫秒)。 * @param {function} [options.callback=null] - 每秒回调事件。 * @param {function} [options.endCallback=null] - 倒计时结束事件。 * @param {function} [options.restart=false] - 再次点击是否重新计时。 */ countDown(key, options) { let op = { duration: options.duration || 10000, // 总倒计时时长(毫秒) callback: options.callback || null, // 每秒回调事件 endCallback: options.endCallback || null, // 倒计时结束事件 restart: options.restart || false, // 是否点击重新计时 }; if (op.restart || !this.counters.has(key)) { const tick = () => { const timer = this.counters.get(key); if (timer.remainingTime <= 0) { clearTimeout(timer.timeoutId); if (op.endCallback) op.endCallback(); this.counters.delete(key); } else { timer.remainingTime -= 1000; if (op.callback) op.callback(Math.ceil(timer.remainingTime / 1000)); timer.timeoutId = setTimeout(tick, 1000); this.counters.set(key, timer); } }; this.counters.set(key, { remainingTime: op.duration, timeoutId: setTimeout(tick, 1000), }); // 立即执行一次回调 if (op.callback) op.callback(Math.ceil(op.duration / 1000)); } } /** * 开始一个倒计时,支持每秒回调、成功和失败事件。 * @param {string} key - 倒计时的唯一标识。 * @param {{fail: fail, success: success, limit: number, run: run, time: number, repetition_time: number}} options - 倒计时的配置选项。 * @param {number} [options.time=10000] - 总倒计时时长(毫秒)。 * @param {number} [options.limit=5] - 连续操作的次数目标。 * @param {function(second, count, boolean):void} [options.run] - 每秒执行的回调函数(剩余秒数,当前被点击次数,是否被点击)。 * @param {function():void} [options.success] - 达到目标次数后的成功回调。 * @param {function():void} [options.fail] - 倒计时结束的失败回调。 * @param {boolean} [options.restart_time=false] - 是否点击重新计时。 * @param {boolean} [options.repetition_time=0] - 重复点击限制时长(毫秒)。 */ secondCountDown(key, options = {}) { let op = { time: options.time || 10000, // 总倒计时长(毫秒) limit: options.limit || 5, // 连续操作的次数目标 run: options.run || null, // 每秒都返回更改页面倒计时文字 success: options.success || null, // 达到目标次数后的成功回调 fail: options.fail || null, // 倒计时结束的失败回调 restart_time: options.restart_time || false, // 是否点击重新计时 repetition_time: options.repetition_time || -1, // 重复点击限制时长(毫秒) -1 为不重置 }; let counter = this.counters.get(key) || { type: 2, count: 0, timer: null, startTime: Date.now(), remainingTime: op.time, inform: true, repetition: null, }; if (counter.timer) { clearTimeout(counter.timer); counter.timer = null; } // 仅当op.restart_time为true时重置时间,点击次数不重置 if (op.restart_time) { counter.startTime = Date.now(); counter.remainingTime = op.time; counter.inform = true; } const tick = () => { let elapsed = Date.now() - counter.startTime; let remaining = op.time - elapsed; if (remaining <= 0) { // 时间到,执行失败事件 op.fail && op.fail(); this.counters.delete(key); } else { // 更新剩余时间并执行运行回调 counter.remainingTime = remaining; op.run && op.run(Math.ceil(remaining / 1000), counter.count, counter.inform); counter.inform = false; counter.timer = setTimeout(tick, 1000); this.counters.set(key, counter); } }; counter.count += 1; counter.inform = true // 每次点击都重新通知 if (counter.count >= op.limit) { // 达到点击次数,执行成功事件 clearTimeout(counter.timer); op.success && op.success(); if (op.repetition_time < 0) { } else if (op.repetition_time === 0) { this.counters.delete(key); } else if (op.repetition_time > 0 && !counter.repetition) { let that = this counter.repetition = setTimeout(() => { that.counters.delete(key); }, op.repetition_time) this.counters.set(key, counter); } } else { // 更新计数器状态 this.counters.set(key, counter); // 继续倒计时 if (!counter.timer) { tick(); } } } clearDebounce(key) { let counter = this.counters.get(key) if (!counter) return; if (counter.timer) clearTimeout(counter.timer) switch (counter.type) { case 2: if (counter.repetition) clearTimeout(counter.repetition) break; } this.counters.delete(key) } } export default Debounce