class Debounce { constructor() { this.timers = new Map(); this.counters = new Map(); this.v3 = new Map(); } // 增加倒计时功能和连续点击触发功能 // key: 唯一键 // callback: 目标事件 // interrupt: 中断事件 // wait: 倒计时时间 /** * 开始一个倒计时,支持每秒回调、成功和失败事件。 * @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] - 重复点击限制时长(毫秒)。 */ static 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(); } } } // 执行防抖操作的方法 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); } // limit: 连续点击次数限制 countDown(key, callback, interrupt, wait = 300, limit = 3) { let counter = this.counters.get(key) || {count: 0, timer: null}; // 如果达到连续点击次数限制,则清除计时器并执行目标事件 if (counter.count + 1 >= limit) { clearTimeout(counter.timer); callback(); this.counters.delete(key); return; } // 更新计数器 counter.count += 1; this.counters.set(key, counter); // 设置或重置倒计时 if (counter.timer) { clearTimeout(counter.timer); } counter.timer = setTimeout(() => { // 倒计时结束后执行中断事件,并重置计数器 interrupt(); this.counters.delete(key); }, wait); this.counters.set(key, counter); } 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