小程序防点击,多次点击事假

本文介绍了一个实用的JavaScript函数——debounce(防抖),用于限制函数的执行频率,避免短时间内频繁触发造成性能问题。通过设置等待时间和选项参数,可以灵活地控制函数在事件触发后的执行时机。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

debounce.js(

import isObject from './isObject.js'

// import root from './.internal/root.js'

 

const root = window;

/**

* Creates a debounced function that delays invoking `func` until after `wait`

* milliseconds have elapsed since the last time the debounced function was

* invoked, or until the next browser frame is drawn. The debounced function

* comes with a `cancel` method to cancel delayed `func` invocations and a

* `flush` method to immediately invoke them. Provide `options` to indicate

* whether `func` should be invoked on the leading and/or trailing edge of the

* `wait` timeout. The `func` is invoked with the last arguments provided to the

* debounced function. Subsequent calls to the debounced function return the

* result of the last `func` invocation.

*

* **Note:** If `leading` and `trailing` options are `true`, `func` is

* invoked on the trailing edge of the timeout only if the debounced function

* is invoked more than once during the `wait` timeout.

*

* If `wait` is `0` and `leading` is `false`, `func` invocation is deferred

* until the next tick, similar to `setTimeout` with a timeout of `0`.

*

* If `wait` is omitted in an environment with `requestAnimationFrame`, `func`

* invocation will be deferred until the next frame is drawn (typically about

* 16ms).

*

* See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)

* for details over the differences between `debounce` and `throttle`.

*

* @since 0.1.0

* @category Function

* @param {Function} func The function to debounce.

* @param {number} [wait=0]

* The number of milliseconds to delay; if omitted, `requestAnimationFrame` is

* used (if available).

* @param {Object} [options={}] The options object.

* @param {boolean} [options.leading=false]

* Specify invoking on the leading edge of the timeout.

* @param {number} [options.maxWait]

* The maximum time `func` is allowed to be delayed before it's invoked.

* @param {boolean} [options.trailing=true]

* Specify invoking on the trailing edge of the timeout.

* @returns {Function} Returns the new debounced function.

* @example

*

* // Avoid costly calculations while the window size is in flux.

* jQuery(window).on('resize', debounce(calculateLayout, 150))

*

* // Invoke `sendMail` when clicked, debouncing subsequent calls.

* jQuery(element).on('click', debounce(sendMail, 300, {

* 'leading': true,

* 'trailing': false

* }))

*

* // Ensure `batchLog` is invoked once after 1 second of debounced calls.

* const debounced = debounce(batchLog, 250, { 'maxWait': 1000 })

* const source = new EventSource('/stream')

* jQuery(source).on('message', debounced)

*

* // Cancel the trailing debounced invocation.

* jQuery(window).on('popstate', debounced.cancel)

*

* // Check for pending invocations.

* const status = debounced.pending() ? "Pending..." : "Ready"

*/

function debounce(func, wait, options) {

let lastArgs,

lastThis,

maxWait,

result,

timerId,

lastCallTime

 

let lastInvokeTime = 0

let leading = false

let maxing = false

let trailing = true

 

// Bypass `requestAnimationFrame` by explicitly setting `wait=0`.

const useRAF = (!wait && wait !== 0 && typeof root.requestAnimationFrame === 'function')

 

if (typeof func != 'function') {

throw new TypeError('Expected a function')

}

wait = +wait || 0

if (isObject(options)) {

leading = !!options.leading

maxing = 'maxWait' in options

maxWait = maxing ? Math.max(+options.maxWait || 0, wait) : maxWait

trailing = 'trailing' in options ? !!options.trailing : trailing

}

 

function invokeFunc(time) {

const args = lastArgs

const thisArg = lastThis

 

lastArgs = lastThis = undefined

lastInvokeTime = time

result = func.apply(thisArg, args)

return result

}

 

function startTimer(pendingFunc, wait) {

if (useRAF) {

return root.requestAnimationFrame(pendingFunc)

}

return setTimeout(pendingFunc, wait)

}

 

function cancelTimer(id) {

if (useRAF) {

return root.cancelAnimationFrame(id)

}

clearTimeout(id)

}

 

function leadingEdge(time) {

// Reset any `maxWait` timer.

lastInvokeTime = time

// Start the timer for the trailing edge.

timerId = startTimer(timerExpired, wait)


 

// Invoke the leading edge.

return leading ? invokeFunc(time) : result

}

 

function remainingWait(time) {

const timeSinceLastCall = time - lastCallTime

const timeSinceLastInvoke = time - lastInvokeTime

const timeWaiting = wait - timeSinceLastCall

 

return maxing

? Math.min(timeWaiting, maxWait - timeSinceLastInvoke)

: timeWaiting

}

 

function shouldInvoke(time) {

const timeSinceLastCall = time - lastCallTime

const timeSinceLastInvoke = time - lastInvokeTime

 

// Either this is the first call, activity has stopped and we're at the

// trailing edge, the system time has gone backwards and we're treating

// it as the trailing edge, or we've hit the `maxWait` limit.

return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||

(timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait))

}

 

function timerExpired() {

const time = Date.now()


 

if (shouldInvoke(time)) {

return trailingEdge(time)

}

 

// Restart the timer.

timerId = startTimer(timerExpired, remainingWait(time))

}

 

function trailingEdge(time) {

timerId = undefined

 

// Only invoke if we have `lastArgs` which means `func` has been

// debounced at least once.

if (trailing && lastArgs) {

return invokeFunc(time)

}

lastArgs = lastThis = undefined

return result

}

 

function cancel() {

if (timerId !== undefined) {

cancelTimer(timerId)

}

lastInvokeTime = 0

lastArgs = lastCallTime = lastThis = timerId = undefined

}

 

function flush() {

return timerId === undefined ? result : trailingEdge(Date.now())

}

 

function pending() {

return timerId !== undefined

}

 

function debounced(...args) {

const time = Date.now()

const isInvoking = shouldInvoke(time)



 

lastArgs = args

lastThis = this

lastCallTime = time

 

if (isInvoking) {


 

if (timerId === undefined) {

return leadingEdge(lastCallTime)

}

if (maxing) {// Handle invocations in a tight loop.timerId = startTimer(timerExpired, wait)return invokeFunc(lastCallTime)}}if (timerId === undefined) {timerId = startTimer(timerExpired, wait)}return result}debounced.cancel = canceldebounced.flush = flushdebounced.pending = pendingreturn debounced}export default debounce)

isObject.js(

/**

* Checks if `value` is the

* [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)

* of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)

*

* @since 0.1.0

* @category Lang

* @param {*} value The value to check.

* @returns {boolean} Returns `true` if `value` is an object, else `false`.

* @example

*

* isObject({})

* // => true

*

* isObject([1, 2, 3])

* // => true

*

* isObject(Function)

* // => true

*

* isObject(null)

* // => false

*/

function isObject(value) {

const type = typeof value

return value != null && (type == 'object' || type == 'function')

}

 

export default isObject

 

 

在需要防点击的页面引入

import debounce from '/debounce'

写法

事件名: debounce(function (e) {

事件处理逻辑

}, 1000, {

leading: true,

trailing: false

}),

 

  • leading,函数在每个等待时延的开始被调用,默认值为false
  • trailing,函数在每个等待时延的结束被调用,默认值是true

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值