JavaScript/JQuery: $(window).resize 调整大小完成后如何触发?
Posted
技术标签:
【中文标题】JavaScript/JQuery: $(window).resize 调整大小完成后如何触发?【英文标题】:JavaScript/JQuery: $(window).resize how to fire AFTER the resize is completed? 【发布时间】:2011-02-20 17:11:24 【问题描述】:我正在使用 JQuery:
$(window).resize(function() ... );
但是,如果用户通过拖动窗口边缘以使其变大/变小来手动调整浏览器窗口的大小,则上面的 .resize
事件会多次触发。
问题:如何在浏览器窗口大小调整完成后调用函数(以便事件只触发一次)?
【问题讨论】:
看到这个答案:***.com/questions/667426/… 它涉及到使用超时来延迟你的函数的执行。 我不知道这是否可能,你可以试试这个插件虽然benalman.com/projects/jquery-resize-plugin 顺便说一句,我注意到这在移动浏览器中非常有用,当用户向下滚动时会逐渐隐藏地址栏,从而调整屏幕大小。我还希望屏幕调整大小只发生在桌面上... 【参考方案1】:这是对 CMS 解决方案的修改,可以在代码中的多个位置调用:
var waitForFinalEvent = (function ()
var timers = ;
return function (callback, ms, uniqueId)
if (!uniqueId)
uniqueId = "Don't call this twice without a uniqueId";
if (timers[uniqueId])
clearTimeout (timers[uniqueId]);
timers[uniqueId] = setTimeout(callback, ms);
;
)();
用法:
$(window).resize(function ()
waitForFinalEvent(function()
alert('Resize...');
//...
, 500, "some unique string");
);
如果您只调用一次,CMS 的解决方案很好,但如果您多次调用它,例如如果您的代码的不同部分设置单独的回调来调整窗口大小,那么它将失败 b/c 他们共享 timer
变量。
通过此修改,您可以为每个回调提供一个唯一 ID,这些唯一 ID 用于将所有超时事件分开。
【讨论】:
我 绝对不可思议! 由于我从您的回答中受益匪浅,我想我为社区其他人分享了您提供的代码的工作原型:jsfiddle.net/h6h2pzpu/3。祝大家愉快! 这一切都很完美,但是它将实际函数的执行延迟了毫秒 (ms),这可能是非常不可取的。 这只是完美的,有没有办法抓住最后一次调整大小而不必在那些毫秒上进行中继?无论如何,这只是节省了我的一天:') 谢谢。【参考方案2】:我更喜欢创建一个事件:
$(window).bind('resizeEnd', function()
//do something, window hasn't changed size in 500ms
);
创建它的方法如下:
$(window).resize(function()
if(this.resizeTO) clearTimeout(this.resizeTO);
this.resizeTO = setTimeout(function()
$(this).trigger('resizeEnd');
, 500);
);
你可以在某个全局 javascript 文件中保存它。
【讨论】:
我使用了这个解决方案。但从长远来看,我想实现与布拉恩的解决方案相同的解决方案。 这允许您在整个地方绑定到该事件,而不仅仅是在一个函数中,假设您有多个页面/.js 文件当然需要对其进行单独的反应 这对我不起作用,但 DusanV 的回答完成了工作【参考方案3】:我使用以下功能来延迟重复动作,它适用于您的情况:
var delay = (function()
var timer = 0;
return function(callback, ms)
clearTimeout (timer);
timer = setTimeout(callback, ms);
;
)();
用法:
$(window).resize(function()
delay(function()
alert('Resize...');
//...
, 500);
);
传递给它的回调函数,只有在最后一次调用延迟之后才会执行,否则计时器将被重置,我发现这对其他用途很有用,比如检测用户何时停止输入等等……
【讨论】:
我认为如果多次使用这种方法可能会失败(例如,如果代码的不同部分设置回调到$(window).resize
),因为它们都将共享timer
变量。有关建议的解决方案,请参阅下面的答案。
非常好!奇迹般有效!喜欢你的答案...简单而优雅!【参考方案4】:
如果您安装了 Underscore.js,您可以:
$(window).resize(_.debounce(function()
alert("Resized");
,500));
【讨论】:
即使你不想包含下划线,至少要抓住它的来源:underscorejs.org/docs/underscore.html#section-67 Debounce 是正确的技术,这只是实现的问题。如果 Underscore/Lodash 已经是项目依赖项,这就是更好的实现。 这就是我现在使用的,【参考方案5】:前面提到的一些解决方案对我不起作用,即使它们更通用。或者,我 found this one 完成了调整窗口大小的工作:
$(window).bind('resize', function(e)
window.resizeEvt;
$(window).resize(function()
clearTimeout(window.resizeEvt);
window.resizeEvt = setTimeout(function()
//code to do after window is resized
, 250);
);
);
【讨论】:
只有你的例子对我有用......上面的其他例子没有!我不确定为什么没有选择您的答案。 我不明白为什么要在 resize 事件中捕获 resize 事件,但它也适用于我...... Mumbo Jumbo,我认为因为其他人专注于泛化,寻找任何此类问题的解决方案(函数的多次调用)。 lightbyte,这是因为每次调用该函数时都必须停止以前的事件。【参考方案6】:非常感谢 David Walsh,这是下划线去抖动的香草版本。
代码:
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
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);
;
;
简单用法:
var myEfficientFn = debounce(function()
// All the taxing stuff you do
, 250);
$(window).on('resize', myEfficientFn);
参考:http://davidwalsh.name/javascript-debounce-function
【讨论】:
【参考方案7】:实际上,据我所知,您无法在关闭调整大小时执行某些操作,这仅仅是因为您不知道未来用户的操作。但是您可以假设两个调整大小事件之间经过的时间,所以如果您等待的时间比这个时间多一点并且没有调整大小,您可以调用您的函数。
想法是我们使用 setTimeout
和它的 id 来保存或删除它。例如,我们知道两次调整大小事件之间的时间是 500 毫秒,因此我们将等待 750 毫秒。
var a;
$(window).resize(function()
clearTimeout(a);
a = setTimeout(function()
// call your function
,750);
);
【讨论】:
【参考方案8】:声明全局延迟监听器:
var resize_timeout;
$(window).on('resize orientationchange', function()
clearTimeout(resize_timeout);
resize_timeout = setTimeout(function()
$(window).trigger('resized');
, 250);
);
下面根据需要使用resized
事件的侦听器:
$(window).on('resized', function()
console.log('resized');
);
【讨论】:
谢谢,这是目前最好的解决方案。我还测试了 250 毫秒是调整窗口大小时的最佳方式。【参考方案9】:它对我有用。 请参阅此解决方案 - https://alvarotrigo.com/blog/firing-resize-event-only-once-when-resizing-is-finished/
var resizeId;
$(window).resize(function()
clearTimeout(resizeId);
resizeId = setTimeout(doneResizing, 500);
);
function doneResizing()
//whatever we want to do
【讨论】:
谢谢@vishwajit76 - 多么好的解决方案【参考方案10】:用于延迟窗口调整大小事件的简单 jQuery 插件。
语法:
添加调整事件大小的新功能
jQuery(window).resizeDelayed( func, delay, id ); // delay and id are optional
删除之前添加的函数(通过声明其 ID)
jQuery(window).resizeDelayed( false, id );
删除所有功能
jQuery(window).resizeDelayed( false );
用法:
// ADD SOME FUNCTIONS TO RESIZE EVENT
jQuery(window).resizeDelayed( function() console.log( 'first event - should run after 0.4 seconds'); , 400, 'id-first-event' );
jQuery(window).resizeDelayed( function() console.log('second event - should run after 1.5 seconds'); , 1500, 'id-second-event' );
jQuery(window).resizeDelayed( function() console.log( 'third event - should run after 3.0 seconds'); , 3000, 'id-third-event' );
// LETS DELETE THE SECOND ONE
jQuery(window).resizeDelayed( false, 'id-second-event' );
// LETS ADD ONE WITH AUTOGENERATED ID(THIS COULDNT BE DELETED LATER) AND DEFAULT TIMEOUT (500ms)
jQuery(window).resizeDelayed( function() console.log('newest event - should run after 0.5 second'); );
// LETS CALL RESIZE EVENT MANUALLY MULTIPLE TIMES (OR YOU CAN RESIZE YOUR BROWSER WINDOW) TO SEE WHAT WILL HAPPEN
jQuery(window).resize().resize().resize().resize().resize().resize().resize();
使用输出:
first event - should run after 0.4 seconds
newest event - should run after 0.5 second
third event - should run after 3.0 seconds
插件:
jQuery.fn.resizeDelayed = (function()
// >>> THIS PART RUNS ONLY ONCE - RIGHT NOW
var rd_funcs = [], rd_counter = 1, foreachResizeFunction = function( func ) for( var index in rd_funcs ) func(index); ;
// REGISTER JQUERY RESIZE EVENT HANDLER
jQuery(window).resize(function()
// SET/RESET TIMEOUT ON EACH REGISTERED FUNCTION
foreachResizeFunction(function(index)
// IF THIS FUNCTION IS MANUALLY DISABLED ( by calling jQuery(window).resizeDelayed(false, 'id') ),
// THEN JUST CONTINUE TO NEXT ONE
if( rd_funcs[index] === false )
return; // CONTINUE;
// IF setTimeout IS ALREADY SET, THAT MEANS THAT WE SHOULD RESET IT BECAUSE ITS CALLED BEFORE DURATION TIME EXPIRES
if( rd_funcs[index].timeout !== false )
clearTimeout( rd_funcs[index].timeout );
// SET NEW TIMEOUT BY RESPECTING DURATION TIME
rd_funcs[index].timeout = setTimeout( rd_funcs[index].func, rd_funcs[index].delay );
);
);
// <<< THIS PART RUNS ONLY ONCE - RIGHT NOW
// RETURN THE FUNCTION WHICH JQUERY SHOULD USE WHEN jQuery(window).resizeDelayed(...) IS CALLED
return function( func_or_false, delay_or_id, id )
// FIRST PARAM SHOULD BE SET!
if( typeof func_or_false == "undefined" )
console.log( 'jQuery(window).resizeDelayed(...) REQUIRES AT LEAST 1 PARAMETER!' );
return this; // RETURN JQUERY OBJECT
// SHOULD WE DELETE THE EXISTING FUNCTION(S) INSTEAD OF CREATING A NEW ONE?
if( func_or_false == false )
// DELETE ALL REGISTERED FUNCTIONS?
if( typeof delay_or_id == "undefined" )
// CLEAR ALL setTimeout's FIRST
foreachResizeFunction(function(index)
if( typeof rd_funcs[index] != "undefined" && rd_funcs[index].timeout !== false )
clearTimeout( rd_funcs[index].timeout );
);
rd_funcs = [];
return this; // RETURN JQUERY OBJECT
// DELETE ONLY THE FUNCTION WITH SPECIFIC ID?
else if( typeof rd_funcs[delay_or_id] != "undefined" )
// CLEAR setTimeout FIRST
if( rd_funcs[delay_or_id].timeout !== false )
clearTimeout( rd_funcs[delay_or_id].timeout );
rd_funcs[delay_or_id] = false;
return this; // RETURN JQUERY OBJECT
// NOW, FIRST PARAM MUST BE THE FUNCTION
if( typeof func_or_false != "function" )
return this; // RETURN JQUERY OBJECT
// SET THE DEFAULT DELAY TIME IF ITS NOT ALREADY SET
if( typeof delay_or_id == "undefined" || isNaN(delay_or_id) )
delay_or_id = 500;
// SET THE DEFAULT ID IF ITS NOT ALREADY SET
if( typeof id == "undefined" )
id = rd_counter;
// ADD NEW FUNCTION TO RESIZE EVENT
rd_funcs[id] =
func : func_or_false,
delay: delay_or_id,
timeout : false
;
rd_counter++;
return this; // RETURN JQUERY OBJECT
)();
【讨论】:
【参考方案11】:假设在窗口调整大小后鼠标光标应该返回到文档,我们可以使用 onmouseover 事件创建类似回调的行为。不要忘记,此解决方案可能无法按预期适用于支持触控的屏幕。
var resizeTimer;
var resized = false;
$(window).resize(function()
clearTimeout(resizeTimer);
resizeTimer = setTimeout(function()
if(!resized)
resized = true;
$(document).mouseover(function()
resized = false;
// do something here
$(this).unbind("mouseover");
)
, 500);
);
【讨论】:
适用于基于鼠标的纯桌面网站,但是如果用户在移动设备上从横向更改为纵向,或者如果他们在触摸屏桌面。 您可以在 Win-Arrow-Left Win-Arrow-Right 等最新 Windows OSE 上借助键盘调整浏览器窗口大小...【参考方案12】:这是我已经实现的:
$(window).resize(function() setTimeout(someFunction, 500); );
如果我们预计调整大小的发生少于500ms
,我们可以clear the setTimeout
祝你好运……
【讨论】:
【参考方案13】:许多解决方案。我试图在 mouuseevent 之后执行该事件,所以我在 ouse 进入窗口后添加了重新加载:
jQuery(window).resize(function()
// this. is window
if( this.resizeTO)
clearTimeout(this.resizeTO)
;
this.resizeTO = setTimeout(function()
jQuery(window).mouseenter(function()
if( jQuery(window).width() < 700 && jQuery(window).width() > 400 )
console.log("mouseenter reloads elements");
// is loading the page
location.reload();
//
; // just mobile
); // mouse fired
, 400); // set Time Ouuut
);
【讨论】:
以上是关于JavaScript/JQuery: $(window).resize 调整大小完成后如何触发?的主要内容,如果未能解决你的问题,请参考以下文章
javascript/jQuery - 啥是 jQuery.fx?
JavaFX,NASA World Wind:如何将 JavaFX 组添加到 NASA World Wind Model