我正在使用jqueryui的滑块小部件 我希望在滑块的滑动事件上运行一个函数,但我只希望它在(700ms)延迟后运行。如果滑块手柄继续移动(即再次触发滑动),那么我希望延迟超时重置。
我试图使用jquery的doTimeout以及setTimeout无济于事。我做的任何事情似乎都会阻止滑块手柄改变位置。
var heavy = {
updatesomething: function() {
//some computationally heavy code
}
}
$('#slider').slider({
min:1, max:99, orientation: 'vertical',
slide: function(event, ui) {
$(this).doTimeout('timeoutid', 700, function() {
heavy.updatesomething(this, ui.value); });
}
});
答案 0 :(得分:0)
使用可用的去抖动实现。以下示例来自davidwalsh blog。另外,不是传递上下文,而是使用apply
,如下所示,使用正确的上下文和参数调用函数。
var heavy = {
updatesomething: function(event, ui) {
console.log(this);
console.log(ui);
}
}
// taken from https://davidwalsh.name/javascript-debounce-function
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this,
args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
$('#slider').slider({
min: 1,
max: 99,
orientation: 'vertical',
slide: debounce(function(event, ui) {
heavy.updatesomething.apply(this, arguments);
//---------------------------^-context ^-- what it says
}, 700)
});
<link href="//code.jquery.com/ui/1.11.4/themes/ui-lightness/jquery-ui.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<div id="slider"></div>
答案 1 :(得分:0)
在这种情况下,去抖动的问题在于,如果用户继续移动滑块,则不会有任何事件。因此,使用限制更有用。
以下示例还包括完整的lodash Throttle和Debounce
'use strict';
/**
* Creates a debounced function that delays invoking `func` until after `wait`
* milliseconds have elapsed since the last time the debounced function was
* invoked. 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 to the next tick, similar to `setTimeout` with a timeout of `0`.
*
* See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
* for details over the differences between `_.debounce` and `_.throttle`.
*
* from lodash - https://github.com/lodash/lodash/blob/4.16.2/lodash.js#L10218
*/
function debounce(func, wait, options) {
if (!options) options = {};
let lastArgs, lastThis, maxWait, result, timerId, lastCallTime, lastInvokeTime = 0,
leading = false,
maxing = false,
trailing = true;
wait = wait || 0;
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,
thisArg = lastThis;
lastArgs = lastThis = undefined;
lastInvokeTime = time;
result = func.apply(thisArg, args);
return result;
}
function leadingEdge(time) {
// Reset any `maxWait` timer.
lastInvokeTime = time;
// Start the timer for the trailing edge.
timerId = setTimeout(timerExpired, wait);
// Invoke the leading edge.
return leading ? invokeFunc(time) : result;
}
function remainingWait(time) {
const timeSinceLastCall = time - lastCallTime,
timeSinceLastInvoke = time - lastInvokeTime,
result = wait - timeSinceLastCall;
return maxing ? Math.min(result, maxWait - timeSinceLastInvoke) : result;
}
function shouldInvoke(time) {
const timeSinceLastCall = time - lastCallTime,
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 = setTimeout(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) {
clearTimeout(timerId);
}
lastInvokeTime = 0;
lastArgs = lastCallTime = lastThis = timerId = undefined;
}
function flush() {
return timerId === undefined ? result : trailingEdge(Date.now());
}
function debounced(...args) {
const time = Date.now(),
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 = setTimeout(timerExpired, wait);
return invokeFunc(lastCallTime);
}
}
if (timerId === undefined) {
timerId = setTimeout(timerExpired, wait);
}
return result;
}
debounced.cancel = cancel;
debounced.flush = flush;
return debounced;
}
/**
* Creates a throttled function that only invokes `func` at most once per
* every `wait` milliseconds. The throttled 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
* throttled function. Subsequent calls to the throttled 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 throttled function
* is invoked more than once during the `wait` timeout.
*
* If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
* until to the next tick, similar to `setTimeout` with a timeout of `0`.
*
* See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
* for details over the differences between `_.throttle` and `_.debounce`.
*/
function throttle(func, wait, options) {
if (!options) options = {};
let leading = true,
trailing = true;
leading = 'leading' in options ? !!options.leading : leading;
trailing = 'trailing' in options ? !!options.trailing : trailing;
return debounce(func, wait, {
'leading': leading,
'maxWait': wait,
'trailing': trailing
});
}
let counter=0;
$('#slider').slider({
min: 1,
max: 99,
orientation: 'vertical',
slide: throttle(function(event, ui) {
$(event.target).slider('option', 'value', ui.value); // making sure value is correct
console.log(ui.value);
}, 100)
});
<link href="//code.jquery.com/ui/1.11.4/themes/ui-lightness/jquery-ui.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<div id="slider"></div>