JQuery: 如何调用 RESIZE 事件只有一次完成调整大小?

当浏览器窗口的大小调整完成后,如何调用函数?

我正在尝试这样做,但是遇到了一些问题,我正在使用 JQuery Resize 事件函数:

$(window).resize(function() {
... // how to call only once the browser has FINISHED resizing?
});

但是,如果用户正在手动调整浏览器窗口的大小,则此函数称为 持续不断。也就是说,它可能会在很短的时间间隔内调用这个函数几十次。

如何只调用调整大小函数 就一次(一旦浏览器窗口完成调整大小) ?

更新

也不必使用全局变量。

94777 次浏览

Here is an example using thejh's instructions

You can store a reference id to any setInterval or setTimeout. Like this:

var loop = setInterval(func, 30);


// some time later clear the interval
clearInterval(loop);

Debounce.

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
} ) );

Note, you can use this method for anything you want to debounce (key events etc).

Tweak the timeout parameter for optimal desired effect.

var lightbox_resize = false;
$(window).resize(function() {
console.log(true);
if (lightbox_resize)
clearTimeout(lightbox_resize);
lightbox_resize = setTimeout(function() {
console.log('resize');
}, 500);
});

You can use setTimeout() and clearTimeout() in conjunction with jQuery.data:

$(window).resize(function() {
clearTimeout($.data(this, 'resizeTimer'));
$.data(this, 'resizeTimer', setTimeout(function() {
//do something
alert("Haven't resized in 200ms!");
}, 200));
});

Update

I wrote an extension to enhance jQuery's default on (& bind)-event-handler. It attaches an event handler function for one or more events to the selected elements if the event was not triggered for a given interval. This is useful if you want to fire a callback only after a delay, like the resize event, or else. 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));

Use it like any other on or bind-event handler, except that you can pass an extra parameter as a last:

$(window).on('resize', function(e) {
console.log(e.type + '-event was 200ms not triggered');
}, 200);

http://jsfiddle.net/ARTsinn/EqqHx/

Just to add to the above, it is common to get unwanted resize events because of scroll bars popping in and out, here is some code to avoid that:

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
});

see jsfiddle

Underscore.js has a couple of great methods for this task: throttle and debounce. Even if you're not using Underscore, take a look at the source of these functions. Here's an example:

var redraw = function() {'redraw logic here'};
var debouncedRedraw = _.debounce(redraw, 750);
$(window).on('resize', debouncedRedraw);

This is my approach:

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);
});
});

The resize-event-listener catches all incoming resize calls, creates a timeout-function for each and saves the timeout-identifier along with an iterating number prepended by 'id-' (to be usable as array key) in the tos-array.

each time, the timout triggers, it calls the fn-function, that checks, if that was the last timeout in the tos array (the fn-function deletes every executed timout). if true (= if(len-1 == 0)), the resizing is finished.

jQuery provides an off method to remove event handler

$(window).resize(function(){
if(magic == true) {
$(window).off('resize', arguments.callee);
}
});