Pārlūkot izejas kodu

无障碍utils:优化debounce功能

任一存 3 gadi atpakaļ
vecāks
revīzija
95601aaf0f
1 mainītis faili ar 77 papildinājumiem un 9 dzēšanām
  1. 77 9
      web/src/utils.js

+ 77 - 9
web/src/utils.js

@@ -218,32 +218,99 @@ function iterateOnFocusableNode(startNode, focusedNodeHandler) {
  *
  * fn: 需要被消抖的函数
  * delay: 消抖时长
- * isImmediateCall: 是在第一次调用时立即执行fn,还是在最后一次调用后等delay时长再调用fn
+ * isImmediateCall: 是否在一组操作中的第一次调用时立即执行fn
+ * isRememberLastCall:是否在一组中最后一次调用后等delay时长再执行fn
  */
-function debounce(fn, delay, isImmediateCall = false) {
+function debounce(fn, delay, isImmediateCall = false, isRememberLastCall = true) {
+  console.assert(isImmediateCall || isRememberLastCall, 'isImmediateCall 和 isRememberLastCall 至少应有一个是true,否则没有意义!')
   let timer = null
   // 上次调用的时刻
   let lastCallTime = 0
 
-  if (isImmediateCall) {
+  if (isImmediateCall && !isRememberLastCall) {
     return function (...args) {
-      const context = this
       const currentTime = Date.now()
       if (currentTime - lastCallTime >= delay) {
-        fn.apply(context, args)
+        fn.apply(this, args)
       }
       lastCallTime = currentTime
     }
-  } else {
+  } else if (!isImmediateCall && isRememberLastCall) {
     return function (...args) {
       if (timer) {
         clearTimeout(timer)
       }
-      const context = this
       timer = setTimeout(() => {
-        fn.apply(context, args)
+        fn.apply(this, args)
       }, delay)
     }
+  } else if (isImmediateCall && isRememberLastCall) {
+    return function (...args) {
+      const currentTime = Date.now()
+      if (currentTime - lastCallTime >= delay) { // 一组操作中的第一次
+        fn.apply(this, args) 
+        lastCallTime = currentTime
+        return
+      } else { // 一组中的后续调用
+        if (timer) { // 在此之前存在中间调用
+          lastCallTime = currentTime
+          clearTimeout(timer)
+        }
+        timer = setTimeout(() => {
+          fn.apply(this, args)
+          lastCallTime = 0
+          timer = null
+        }, delay)
+      }
+    }
+  } else {
+    console.error('不应该执行到这里!')
+  }
+}
+
+class DebounceScheduler {
+  constructor(fn, delay, context, isImmediateCall = false) {
+    this.job = fn
+    this.delay = delay
+    this.context = context
+    this.timer = null
+    this.lastCallTime = 0
+    this.isImmediateCall = isImmediateCall
+  }
+  planToDo(...args) {
+    if (!this.isImmediateCall) {
+      if (this.timer) {
+        clearTimeout(this.timer)
+        this.timer = null
+      }
+      this.timer = setTimeout(() => {
+        this.job.apply(this.context, args)
+      }, this.delay)
+    } else {
+      const currentTime = Date.now()
+      if (currentTime - this.lastCallTime >= this.delay) { // 一组操作中的第一次
+        this.job.apply(this.context, args) 
+        this.lastCallTime = currentTime
+        return
+      } else { // 一组中的后续调用
+        if (this.timer) { // 在此之前存在中间调用
+          this.lastCallTime = currentTime
+          clearTimeout(this.timer)
+          this.timer = null
+        }
+        this.timer = setTimeout(() => {
+          this.job.apply(this.context, args)
+          this.lastCallTime = 0
+          this.timer = null
+        }, this.delay)
+      }
+    }
+  }
+  cancel() {
+    if (this.timer) {
+      clearTimeout(this.timer)
+      this.timer = null
+    }
   }
 }
 
@@ -251,7 +318,8 @@ export default {
   mapTags,
   extractTextForMagnify,
   isSameObject,
+  getAndFocusNextNodeWithCustomAttribute,
   iterateOnFocusableNode,
   debounce,
-  getAndFocusNextNodeWithCustomAttribute,
+  DebounceScheduler,
 }