JQuery: Как вызвать событие RESIZE только после его завершения?
Как вызвать функцию после того, как в окнах браузера завершено изменение размера?
Я пытаюсь сделать это так, но у меня проблемы. Я использую функцию события JQuery Resize:
$(window).resize(function() {
... // how to call only once the browser has FINISHED resizing?
});
Однако эта функция вызывается постоянно, если пользователь вручную изменяет размер окна браузера. Это значит, что она может вызывать эту функцию десятки раз за короткий промежуток времени.
Как я могу вызвать функцию изменения размера только один раз (как только окно браузера завершит изменение размера)?
ОБНОВИТЬ
Также без использования глобальной переменной.
8 ответов
Вот пример использования инструкций thejh
Вы можете сохранить ссылочный идентификатор для любого 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
)-обработчик события. Он присоединяет функцию обработчика событий для одного или нескольких событий к выбранным элементам, если событие не было запущено в течение заданного интервала. Это полезно, если вы хотите запустить обратный вызов только после задержки, например, события изменения размера, или иначе. 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);
В дополнение к вышесказанному, обычное получение нежелательных событий изменения размера из-за появления и исчезновения полос прокрутки. Вот некоторый код, чтобы избежать этого:
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
var lightbox_resize = false;
$(window).resize(function() {
console.log(true);
if (lightbox_resize)
clearTimeout(lightbox_resize);
lightbox_resize = setTimeout(function() {
console.log('resize');
}, 500);
});
http://underscorejs.org/ имеет несколько отличных методов для этой задачи: 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);
});
});
Прослушиватель события изменения размера перехватывает все входящие вызовы изменения размера, создает функцию тайм-аута для каждого и сохраняет идентификатор тайм-аута вместе с итерационным числом, которому предшествует 'id-'
(для использования в качестве ключа массива) в tos
-array.
каждый раз срабатывает тайм-аут, он вызывает fn
-функция, которая проверяет, был ли это последний тайм-аут в tos
массив (функция fn удаляет каждый выполненный тайм-аут). если верно (= if(len-1 == 0)
), изменение размера завершено.
JQuery обеспечивает off
метод для удаления обработчика событий
$(window).resize(function(){
if(magic == true) {
$(window).off('resize', arguments.callee);
}
});