如何等待'结局'& # 39;调整# 39;事件,然后才执行操作?

所以我目前使用的是:

$(window).resize(function(){resizedw();});

但是在调整大小过程中,这个函数会被调用很多次。是否有可能在事件结束时捕获事件?

291493 次浏览

Internet Explorer提供了resizeEnd事件。其他浏览器会在您调整大小时多次触发调整大小事件。

这里还有其他很好的答案,展示了如何使用setTimeout和来自lodash和underscore的< em > .throttle< / em > .debounce方法,所以我将提到Ben Alman的throttle-debounce jQuery插件 . jQuery插件,它实现了你想要的东西。

假设你有这样一个函数,你想在调整大小后触发:

function onResize() {
console.log("Resize just happened!");
};
< p > 节流阀的例子 < br > 在下面的例子中,在窗口大小调整过程中,onResize()只会每250毫秒调用一次
$(window).resize( $.throttle( 250, onResize) );
< p > 防反跳的例子 < br > 在下面的例子中,onResize()只会在窗口调整动作结束时被调用一次。这达到了与@Mark在他的回答中呈现的相同的结果
$(window).resize( $.debounce( 250, onResize) );

你可以使用setTimeout()clearTimeout()

function resizedw(){
// Haven't resized in 100ms!
}


var doit;
window.onresize = function(){
clearTimeout(doit);
doit = setTimeout(resizedw, 100);
};

关于jsfiddle. jsfiddle. rref ="http://jsfiddle.net/mblase75/fq882/197/"的代码示例。

好吧,就窗口管理器而言,每个调整大小事件都是它自己的消息,具有不同的开始和结束,所以从技术上讲,每次窗口调整大小时,它都会结束。

话虽如此,也许你想推迟你的延续?举个例子。

var t = -1;
function doResize()
{
document.write('resize');
}
$(document).ready(function(){
$(window).resize(function(){
clearTimeout(t);
t = setTimeout(doResize, 1000);
});
});

我很幸运地使用了以下推荐:http://forum.jquery.com/topic/the-resizeend-event

下面是代码,所以你不需要挖掘他的帖子的链接&来源:

var rtime;
var timeout = false;
var delta = 200;
$(window).resize(function() {
rtime = new Date();
if (timeout === false) {
timeout = true;
setTimeout(resizeend, delta);
}
});


function resizeend() {
if (new Date() - rtime < delta) {
setTimeout(resizeend, delta);
} else {
timeout = false;
alert('Done resizing');
}
}

谢谢森那美。Vidas for code!

你可以将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)事件处理程序。如果事件在给定的时间间隔内没有触发,它将一个或多个事件的事件处理程序函数附加到选定的元素。如果您希望仅在延迟之后触发回调,例如resize事件或其他,则这非常有用。 https://github.com/yckart/jquery.unevent.js < / p >
;(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或__abc1 -事件处理程序一样使用它,除非你可以传递一个额外的参数作为最后一个参数:

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

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

因为选择的答案实际上没有工作。如果你没有使用jquery,这里有一个简单的节流函数的例子,如何使用它来调整窗口大小

    function throttle(end,delta) {


var base = this;


base.wait = false;
base.delta = 200;
base.end = end;


base.trigger = function(context) {


//only allow if we aren't waiting for another event
if ( !base.wait ) {


//signal we already have a resize event
base.wait = true;


//if we are trying to resize and we
setTimeout(function() {


//call the end function
if(base.end) base.end.call(context);


//reset the resize trigger
base.wait = false;
}, base.delta);
}
}
};


var windowResize = new throttle(function() {console.log('throttle resize');},200);


window.onresize = function(event) {
windowResize.trigger();
}

我自己写了一个小包装函数…

onResize  =   function(fn) {
if(!fn || typeof fn != 'function')
return 0;


var args    = Array.prototype.slice.call(arguments, 1);


onResize.fnArr    = onResize.fnArr || [];
onResize.fnArr.push([fn, args]);


onResize.loop   = function() {
$.each(onResize.fnArr, function(index, fnWithArgs) {
fnWithArgs[0].apply(undefined, fnWithArgs[1]);
});
};


$(window).on('resize', function(e) {
window.clearTimeout(onResize.timeout);
onResize.timeout    = window.setTimeout("onResize.loop();", 300);
});
};

用法如下:

var testFn  = function(arg1, arg2) {
console.log('[testFn] arg1: '+arg1);
console.log('[testFn] arg2: '+arg2);
};


// document ready
$(function() {
onResize(testFn, 'argument1', 'argument2');
});
(function(){
var special = jQuery.event.special,
uid1 = 'D' + (+new Date()),
uid2 = 'D' + (+new Date() + 1);


special.resizestart = {
setup: function() {
var timer,
handler =  function(evt) {
var _self = this,
_args = arguments;
if (timer) {
clearTimeout(timer);
} else {
evt.type = 'resizestart';
jQuery.event.handle.apply(_self, _args);
}


timer = setTimeout( function(){
timer = null;
}, special.resizestop.latency);
};
jQuery(this).bind('resize', handler).data(uid1, handler);
},
teardown: function(){
jQuery(this).unbind( 'resize', jQuery(this).data(uid1) );
}
};


special.resizestop = {
latency: 200,
setup: function() {
var timer,
handler = function(evt) {
var _self = this,
_args = arguments;
if (timer) {
clearTimeout(timer);
}
timer = setTimeout( function(){
timer = null;
evt.type = 'resizestop';
jQuery.event.handle.apply(_self, _args);
}, special.resizestop.latency);
};


jQuery(this).bind('resize', handler).data(uid2, handler);
},
teardown: function() {
jQuery(this).unbind( 'resize', jQuery(this).data(uid2) );
}
};
})();


$(window).bind('resizestop',function(){
//...
});

您可以将引用id存储到任何setInterval或setTimeout。是这样的:

var loop = setInterval(func, 30);


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

要在不使用“全局”变量的情况下做到这一点,可以向函数本身添加一个局部变量。例:

$(window).resize(function() {
clearTimeout(this.id);
this.id = setTimeout(doneResizing, 500);
});


function doneResizing(){
$("body").append("<br/>done!");
}

有一个优雅的解决方案使用Underscore.js,所以,如果你在你的项目中使用它,你可以做以下-

$( window ).resize( _.debounce( resizedw, 500 ) );

这应该足够了:)但是,如果你有兴趣阅读更多,你可以查看我的博客文章- http://rifatnabi.com/post/detect-end-of-jquery-resize-event-using-underscore-debounce(deadlink)

更新!

我创造的更好的选择是: https://stackoverflow.com/a/23692008/2829600 < a href = " https://stackoverflow.com/a/23692008/2829600 " > < / > (支持“删除函数”)

原来的帖子:

我写了这个简单的函数来处理执行中的延迟,在jQuery .scroll()和.resize()中很有用,所以callback_f只会对特定的id字符串运行一次。

function delay_exec( id, wait_time, callback_f ){


// IF WAIT TIME IS NOT ENTERED IN FUNCTION CALL,
// SET IT TO DEFAULT VALUE: 0.5 SECOND
if( typeof wait_time === "undefined" )
wait_time = 500;


// CREATE GLOBAL ARRAY(IF ITS NOT ALREADY CREATED)
// WHERE WE STORE CURRENTLY RUNNING setTimeout() FUNCTION FOR THIS ID
if( typeof window['delay_exec'] === "undefined" )
window['delay_exec'] = [];


// RESET CURRENTLY RUNNING setTimeout() FUNCTION FOR THIS ID,
// SO IN THAT WAY WE ARE SURE THAT callback_f WILL RUN ONLY ONE TIME
// ( ON LATEST CALL ON delay_exec FUNCTION WITH SAME ID  )
if( typeof window['delay_exec'][id] !== "undefined" )
clearTimeout( window['delay_exec'][id] );


// SET NEW TIMEOUT AND EXECUTE callback_f WHEN wait_time EXPIRES,
// BUT ONLY IF THERE ISNT ANY MORE FUTURE CALLS ( IN wait_time PERIOD )
// TO delay_exec FUNCTION WITH SAME ID AS CURRENT ONE
window['delay_exec'][id] = setTimeout( callback_f , wait_time );
}




// USAGE


jQuery(window).resize(function() {


delay_exec('test1', 1000, function(){
console.log('1st call to delay "test1" successfully executed!');
});


delay_exec('test1', 1000, function(){
console.log('2nd call to delay "test1" successfully executed!');
});


delay_exec('test1', 1000, function(){
console.log('3rd call to delay "test1" successfully executed!');
});


delay_exec('test2', 1000, function(){
console.log('1st call to delay "test2" successfully executed!');
});


delay_exec('test3', 1000, function(){
console.log('1st call to delay "test3" successfully executed!');
});


});


/* RESULT
3rd call to delay "test1" successfully executed!
1st call to delay "test2" successfully executed!
1st call to delay "test3" successfully executed!
*/

这是对上面Dolan代码的修改,我添加了一个功能,在调整大小开始时检查窗口大小,并将其与调整大小结束时的大小进行比较,如果大小大于或小于边缘(例如。1000)然后重新加载。

var rtime = new Date(1, 1, 2000, 12,00,00);
var timeout = false;
var delta = 200;
var windowsize = $window.width();
var windowsizeInitial = $window.width();


$(window).on('resize',function() {
windowsize = $window.width();
rtime = new Date();
if (timeout === false) {
timeout = true;
setTimeout(resizeend, delta);
}
});


function resizeend() {
if (new Date() - rtime < delta) {
setTimeout(resizeend, delta);
return false;
} else {
if (windowsizeInitial > 1000 && windowsize > 1000 ) {
setTimeout(resizeend, delta);
return false;
}
if (windowsizeInitial < 1001 && windowsize < 1001 ) {
setTimeout(resizeend, delta);
return false;
} else {
timeout = false;
location.reload();
}
}
windowsizeInitial = $window.width();
return false;
}

这适用于我,因为我不想使用任何插件。

$(window).resize(function() {
var originalWindowSize = 0;
var currentWidth = 0;


var setFn = function () {
originalWindowSize = $(window).width();
};


var checkFn = function () {
setTimeout(function () {
currentWidth = $(window).width();
if (currentWidth === originalWindowSize) {
console.info("same? = yes")
// execute code
} else {
console.info("same? = no");
// do nothing
}
}, 500)
};
setFn();
checkFn();
});

在窗口重新大小调用“setFn”获得窗口的宽度,并保存为“originalWindowSize”。然后调用“checkFn”,在500ms(或您的首选项)后获得当前窗口大小,并将原始窗口与当前窗口进行比较,如果它们不相同,则窗口仍在重新调整大小。不要忘记在生产环境中删除控制台消息,并且(可选)可以使“setFn”自动执行。

var resizeTimer;
$( window ).resize(function() {
if(resizeTimer){
clearTimeout(resizeTimer);
}
resizeTimer = setTimeout(function() {
//your code here
resizeTimer = null;
}, 200);
});

这为我试图在chrome做什么工作。这将不会触发回调直到200ms后最后调整大小事件。

这是我根据@Mark Coleman的答案写的代码:

$(window).resize(function() {
clearTimeout(window.resizedFinished);
window.resizedFinished = setTimeout(function(){
console.log('Resized finished.');
}, 250);
});

谢谢马克!

窗口的ResizeStartResizeEnd事件

http://jsfiddle.net/04fLy8t4/

我实现了一个函数,它在用户DOM元素上触发两个事件:

  1. resizestart
  2. resizeend

代码:

var resizeEventsTrigger = (function () {
function triggerResizeStart($el) {
$el.trigger('resizestart');
isStart = !isStart;
}


function triggerResizeEnd($el) {
clearTimeout(timeoutId);
timeoutId = setTimeout(function () {
$el.trigger('resizeend');
isStart = !isStart;
}, delay);
}


var isStart = true;
var delay = 200;
var timeoutId;


return function ($el) {
isStart ? triggerResizeStart($el) : triggerResizeEnd($el);
};


})();


$("#my").on('resizestart', function () {
console.log('resize start');
});
$("#my").on('resizeend', function () {
console.log('resize end');
});


window.onresize = function () {
resizeEventsTrigger( $("#my") );
};

下面是一个非常简单的脚本,可以在窗口对象上触发'resizestart'和'resizeend'事件。

没有必要在日期和时间上浪费时间。

d变量表示在触发调整大小结束事件之前,调整大小事件之间的毫秒数,你可以使用这个变量来改变结束事件的灵敏度。

要收听这些事件,你所需要做的就是:

resizestart: $(window).on('resizestart', function(event){console.log('Resize Start!');});

< p > resizeend: $(window).on('resizeend', function(event){console.log('Resize End!');}); < / p >
(function ($) {
var d = 250, t = null, e = null, h, r = false;


h = function () {
r = false;
$(window).trigger('resizeend', e);
};


$(window).on('resize', function (event) {
e = event || e;
clearTimeout(t);


if (!r) {
$(window).trigger('resizestart', e);
r = true;
}


t = setTimeout(h, d);
});
}(jQuery));
var flag=true;
var timeloop;


$(window).resize(function(){
rtime=new Date();
if(flag){
flag=false;
timeloop=setInterval(function(){
if(new Date()-rtime>100)
myAction();
},100);
}
})
function myAction(){
clearInterval(timeloop);
flag=true;
//any other code...
}

Mark Coleman的答案当然比选定的答案要好得多,但如果你想避免超时ID的全局变量(Mark回答中的doit变量),你可以做以下其中一种:

(1)使用立即调用的函数表达式(IIFE)来创建闭包。

$(window).resize((function() { // This function is immediately invoked
// and returns the closure function.
var timeoutId;
return function() {
clearTimeout(timeoutId);
timeoutId = setTimeout(function() {
timeoutId = null; // You could leave this line out.
// Code to execute on resize goes here.
}, 100);
};
})());

(2)使用事件处理函数的属性。

$(window).resize(function() {
var thisFunction = arguments.callee;
clearTimeout(thisFunction.timeoutId);
thisFunction.timeoutId = setTimeout(function() {
thisFunction.timeoutId = null; // You could leave this line out.
// Code to execute on resize goes here.
}, 100);
});

我不知道我的代码是否适用于其他人,但它对我来说真的很好。我通过分析Dolan Antenucci的代码得到了这个想法,因为他的版本不适合我,我真的希望它能对别人有所帮助。

var tranStatus = false;
$(window).resizeend(200, function(){
$(".cat-name, .category").removeAttr("style");
//clearTimeout(homeResize);
$("*").one("webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend",function(event) {
tranStatus = true;
});
processResize();
});


function processResize(){
homeResize = setInterval(function(){
if(tranStatus===false){
console.log("not yet");
$("*").one("webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend",function(event) {
tranStatus = true;
});
}else{
text_height();
clearInterval(homeResize);
}
},200);
}

一种解决方案是用函数扩展jQuery,例如:resized

$.fn.resized = function (callback, timeout) {
$(this).resize(function () {
var $this = $(this);
if ($this.data('resizeTimeout')) {
clearTimeout($this.data('resizeTimeout'));
}
$this.data('resizeTimeout', setTimeout(callback, timeout));
});
};

示例用法:

< p > <代码> 美元(窗口)。大小(myHandler, 300); < /代码> < / p >

我写了一个函数,当包装在任何调整大小事件时传递一个函数。它使用一个间隔,这样调整大小甚至不会不断地创建超时事件。这允许它独立于调整大小事件(而不是应该在生产中删除的日志项)执行。

https://github.com/UniWrighte/resizeOnEnd/blob/master/resizeOnEnd.js

        $(window).resize(function(){
//call to resizeEnd function to execute function on resize end.
//can be passed as function name or anonymous function
resizeEnd(function(){






});


});


//global variables for reference outside of interval
var interval = null;
var width = $(window).width();
var numi = 0; //can be removed in production
function resizeEnd(functionCall){
//check for null interval
if(!interval){
//set to new interval
interval = setInterval(function(){
//get width to compare
width2 = $(window).width();
//if stored width equals new width
if(width === width2){
//clear interval, set to null, and call passed function
clearInterval(interval);
interval = null; //precaution
functionCall();


}
//set width to compare on next interval after half a second
width = $(window).width();
}, 500);


}else{
//logging that should be removed in production
console.log("function call " + numi++ + " and inteval set skipped");


}

这是我用来延迟重复操作的,它可以在你的代码中的多个地方调用:

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

用法:

$(window).resize(function () {
debounce(function() {
//...
}, 500);
});

有一个比计算两次调用之间的增量时间更简单的方法来在调整大小结束时执行函数,简单地像这样做:

var resizeId;
$(window).resize(function() {
clearTimeout(resizeId);
resizeId = setTimeout(resizedEnded, 500);
});


function resizedEnded(){
...
}

Angular2的等价:

private resizeId;
@HostListener('window:resize', ['$event'])
onResized(event: Event) {
clearTimeout(this.resizeId);
this.resizeId = setTimeout(() => {
// Your callback method here.
}, 500);
}

对于angular方法,使用setTimeout中的() => { }符号来保留作用域,否则将无法进行任何函数调用或使用this

我猜我的情况可能与其他一些人不同,但我有一个问题,只有在iOS上的方向变化,但希望调整大小事件立即运行。我使用了ScreenOrientation API:

screen.orientation.addEventListener('change', (e) => {});

我采取了稍微不同的策略,并依赖mouseUp作为resize事件的结束。在documentReady上调用trackSize,然后设置wide的初始值。

  var THRESHOLD = 784;
var TALL = 125, SHORT = 50;
var wide = (window.document.body.clientWidth >= THRESHOLD );


function trackSize() {
if( !wide ) {
setHeight( TALL );
} else {
setHeight( SHORT );
}
parent.window.addEventListener('resize', onResize);
}
function onResize(e) {
parent.window.removeEventListener('resize', onResize);
parent.window.addEventListener('mouseup', onMouseUp) ;
}
function onMouseUp(e) {
parent.window.removeEventListener('mouseup', onMouseUp);
wide = (window.document.body.clientWidth >= THRESHOLD);
trackSize();
}

在设置了窗口的初始高度之后,我们开始监听resize事件。当它开始时,我们停止监听并开始监听mouseUp事件。因此,我们知道mouseUp将结束调整大小。在mouseUp中,我们停止监听并根据窗口的宽度设置一个切换,然后循环回trackSize

trackSize首先根据切换设置窗口的高度——如果低于阈值,则增加高度(因为Bootstrap列的堆栈宽度较小),否则设置为标准。然后我们再听下一个resize事件。

警告:这个解决方案并不真正适用于使用最大化或恢复窗口按钮立即调整大小。也许添加一个类似isMouseDown的测试并绕过鼠标监听器就足够了——我还没有测试过。