Ответ 1
Вот пример, используя инструкции jh
Вы можете сохранить ссылочный идентификатор для любого setInterval или setTimeout. Вот так:
var loop = setInterval(func, 30);
// some time later clear the interval
clearInterval(loop);
Как мне вызвать функцию после того, как окна браузера имеют ЗАВЕРШЕНО изменение размера?
Я пытаюсь сделать это так, но у меня проблемы. Я использую функцию события JQuery Resize:
$(window).resize(function() {
... // how to call only once the browser has FINISHED resizing?
});
Однако эта функция вызывается непрерывно, если пользователь вручную изменяет размер окна браузера. Это означает, что это может вызвать эту функцию десятки раз за короткий промежуток времени.
Как я могу вызвать функцию изменения размера только один раз (как только окно браузера закончило изменение размера)?
UPDATE
Также не нужно использовать глобальную переменную.
Вот пример, используя инструкции jh
Вы можете сохранить ссылочный идентификатор для любого setInterval или setTimeout. Вот так:
var loop = setInterval(func, 30);
// some time later clear the interval
clearInterval(loop);
function debouncer( func , timeout ) {
var timeoutID , timeout = timeout || 200;
return function () {
var scope = this , args = arguments;
clearTimeout( timeoutID );
timeoutID = setTimeout( function () {
func.apply( scope , Array.prototype.slice.call( args ) );
} , timeout );
}
}
$( window ).resize( debouncer( function ( e ) {
// do stuff
} ) );
Примечание. Вы можете использовать этот метод для всего, что вы хотите отменить (ключевые события и т.д.).
Измените параметр таймаута для оптимального желаемого эффекта.
Вы можете использовать setTimeout()
и clearTimeout()
в сочетании с jQuery.data
:
$(window).resize(function() {
clearTimeout($.data(this, 'resizeTimer'));
$.data(this, 'resizeTimer', setTimeout(function() {
//do something
alert("Haven't resized in 200ms!");
}, 200));
});
Обновление
Я написал расширение для улучшения jQuery по умолчанию on
(& bind
) - event-обработчик. Он прикрепляет функцию обработчика событий для одного или нескольких событий к выбранным элементам, если событие не было инициировано для заданного интервала. Это полезно, если вы хотите активировать обратный вызов только после задержки, например событие изменения размера или другое.
https://github.com/yckart/jquery.unevent.js
;(function ($) {
var methods = { on: $.fn.on, bind: $.fn.bind };
$.each(methods, function(k){
$.fn[k] = function () {
var args = [].slice.call(arguments),
delay = args.pop(),
fn = args.pop(),
timer;
args.push(function () {
var self = this,
arg = arguments;
clearTimeout(timer);
timer = setTimeout(function(){
fn.apply(self, [].slice.call(arg));
}, delay);
});
return methods[k].apply(this, isNaN(delay) ? arguments : args);
};
});
}(jQuery));
Используйте его, как и любой другой обработчик on
или bind
-event, за исключением того, что вы можете передать дополнительный параметр как последний:
$(window).on('resize', function(e) {
console.log(e.type + '-event was 200ms not triggered');
}, 200);
var lightbox_resize = false;
$(window).resize(function() {
console.log(true);
if (lightbox_resize)
clearTimeout(lightbox_resize);
lightbox_resize = setTimeout(function() {
console.log('resize');
}, 500);
});
Чтобы добавить к вышесказанному, обычно возникают нежелательные изменения размера, поскольку полосы прокрутки появляются и выходят, вот какой код следует избегать:
function registerResize(f) {
$(window).resize(function() {
clearTimeout(this.resizeTimeout);
this.resizeTimeout = setTimeout(function() {
var oldOverflow = document.body.style.overflow;
document.body.style.overflow = "hidden";
var currHeight = $(window).height(),
currWidth = $(window).width();
document.body.style.overflow = oldOverflow;
var prevUndefined = (typeof this.prevHeight === 'undefined' || typeof this.prevWidth === 'undefined');
if (prevUndefined || this.prevHeight !== currHeight || this.prevWidth !== currWidth) {
//console.log('Window size ' + (prevUndefined ? '' : this.prevHeight + "," + this.prevWidth) + " -> " + currHeight + "," + currWidth);
this.prevHeight = currHeight;
this.prevWidth = currWidth;
f(currHeight, currWidth);
}
}, 200);
});
$(window).resize(); // initialize
}
registerResize(function(height, width) {
// this will be called only once per resize regardless of scrollbars changes
});
см. jsfiddle
Underscore.js содержит несколько отличных методов для этой задачи: throttle
и debounce
. Даже если вы не используете Underscore, посмотрите на источник этих функций. Вот пример:
var redraw = function() {'redraw logic here'};
var debouncedRedraw = _.debounce(redraw, 750);
$(window).on('resize', debouncedRedraw);
Это мой подход:
document.addEventListener('DOMContentLoaded', function(){
var tos = {};
var idi = 0;
var fn = function(id)
{
var len = Object.keys(tos).length;
if(len == 0)
return;
to = tos[id];
delete tos[id];
if(len-1 == 0)
console.log('Resize finished trigger');
};
window.addEventListener('resize', function(){
idi++;
var id = 'id-'+idi;
tos[id] = window.setTimeout(function(){fn(id)}, 500);
});
});
Функция resize-event-listener ловит все входящие вызовы с изменением размера, создает функцию тайм-аута для каждого и сохраняет идентификатор тайм-аута вместе с номером повтора, добавленным 'id-'
(для использования в качестве ключа массива) в tos
-array.
каждый раз, триггеры времени, он вызывает функцию fn
, которая проверяет, был ли это последний тайм-аут в массиве tos
(функция fn удаляет каждый выполненный тайм-аут). если true (= if(len-1 == 0)
), изменение размера завершено.
jQuery предоставляет метод off
для удаления обработчика событий
$(window).resize(function(){
if(magic == true) {
$(window).off('resize', arguments.callee);
}
});