123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- 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
|