debounce.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. class Debounce {
  2. constructor() {
  3. this.timers = new Map();
  4. this.counters = new Map();
  5. this.v3 = new Map();
  6. }
  7. // 增加倒计时功能和连续点击触发功能
  8. // key: 唯一键
  9. // callback: 目标事件
  10. // interrupt: 中断事件
  11. // wait: 倒计时时间
  12. /**
  13. * 开始一个倒计时,支持每秒回调、成功和失败事件。
  14. * @param {string} key - 倒计时的唯一标识。
  15. * @param {{fail: fail, success: success, limit: number, run: run, time: number, repetition_time: number}} options - 倒计时的配置选项。
  16. * @param {number} [options.time=10000] - 总倒计时时长(毫秒)。
  17. * @param {number} [options.limit=5] - 连续操作的次数目标。
  18. * @param {function(second, count, boolean):void} [options.run] - 每秒执行的回调函数(剩余秒数,当前被点击次数,是否被点击)。
  19. * @param {function():void} [options.success] - 达到目标次数后的成功回调。
  20. * @param {function():void} [options.fail] - 倒计时结束的失败回调。
  21. * @param {boolean} [options.restart_time=false] - 是否点击重新计时。
  22. * @param {boolean} [options.repetition_time=0] - 重复点击限制时长(毫秒)。
  23. */
  24. static secondCountDown(key, options = {}) {
  25. let op = {
  26. time: options.time || 10000, // 总倒计时长(毫秒)
  27. limit: options.limit || 5, // 连续操作的次数目标
  28. run: options.run || null, // 每秒都返回更改页面倒计时文字
  29. success: options.success || null, // 达到目标次数后的成功回调
  30. fail: options.fail || null, // 倒计时结束的失败回调
  31. restart_time: options.restart_time || false, // 是否点击重新计时
  32. repetition_time: options.repetition_time || -1, // 重复点击限制时长(毫秒) -1 为不重置
  33. };
  34. let counter = this.counters.get(key) || {
  35. type: 2,
  36. count: 0,
  37. timer: null,
  38. startTime: Date.now(),
  39. remainingTime: op.time,
  40. inform: true,
  41. repetition: null,
  42. };
  43. if (counter.timer) {
  44. clearTimeout(counter.timer);
  45. counter.timer = null;
  46. }
  47. // 仅当op.restart_time为true时重置时间,点击次数不重置
  48. if (op.restart_time) {
  49. counter.startTime = Date.now();
  50. counter.remainingTime = op.time;
  51. counter.inform = true;
  52. }
  53. const tick = () => {
  54. let elapsed = Date.now() - counter.startTime;
  55. let remaining = op.time - elapsed;
  56. if (remaining <= 0) {
  57. // 时间到,执行失败事件
  58. op.fail && op.fail();
  59. this.counters.delete(key);
  60. } else {
  61. // 更新剩余时间并执行运行回调
  62. counter.remainingTime = remaining;
  63. op.run && op.run(Math.ceil(remaining / 1000), counter.count, counter.inform);
  64. counter.inform = false;
  65. counter.timer = setTimeout(tick, 1000);
  66. this.counters.set(key, counter);
  67. }
  68. };
  69. counter.count += 1;
  70. counter.inform = true // 每次点击都重新通知
  71. if (counter.count >= op.limit) {
  72. // 达到点击次数,执行成功事件
  73. clearTimeout(counter.timer);
  74. op.success && op.success();
  75. if (op.repetition_time < 0) {
  76. } else if (op.repetition_time === 0) {
  77. this.counters.delete(key);
  78. } else if (op.repetition_time > 0 && !counter.repetition) {
  79. let that = this
  80. counter.repetition = setTimeout(() => {
  81. that.counters.delete(key);
  82. }, op.repetition_time)
  83. this.counters.set(key, counter);
  84. }
  85. } else {
  86. // 更新计数器状态
  87. this.counters.set(key, counter);
  88. // 继续倒计时
  89. if (!counter.timer) {
  90. tick();
  91. }
  92. }
  93. }
  94. // 执行防抖操作的方法
  95. do(key, callback, wait = 300) {
  96. if (this.timers.has(key)) {
  97. clearTimeout(this.timers.get(key));
  98. }
  99. const timer = setTimeout(() => {
  100. callback();
  101. this.timers.delete(key);
  102. }, wait);
  103. this.timers.set(key, timer);
  104. }
  105. // limit: 连续点击次数限制
  106. countDown(key, callback, interrupt, wait = 300, limit = 3) {
  107. let counter = this.counters.get(key) || {count: 0, timer: null};
  108. // 如果达到连续点击次数限制,则清除计时器并执行目标事件
  109. if (counter.count + 1 >= limit) {
  110. clearTimeout(counter.timer);
  111. callback();
  112. this.counters.delete(key);
  113. return;
  114. }
  115. // 更新计数器
  116. counter.count += 1;
  117. this.counters.set(key, counter);
  118. // 设置或重置倒计时
  119. if (counter.timer) {
  120. clearTimeout(counter.timer);
  121. }
  122. counter.timer = setTimeout(() => {
  123. // 倒计时结束后执行中断事件,并重置计数器
  124. interrupt();
  125. this.counters.delete(key);
  126. }, wait);
  127. this.counters.set(key, counter);
  128. }
  129. clearDebounce(key) {
  130. let counter = this.counters.get(key)
  131. if (!counter) return;
  132. if (counter.timer) clearTimeout(counter.timer)
  133. switch (counter.type) {
  134. case 2:
  135. if (counter.repetition) clearTimeout(counter.repetition)
  136. break;
  137. }
  138. this.counters.delete(key)
  139. }
  140. }
  141. export default Debounce