JavaScript / JQuery:$(window).resize调整大小完成后如何触发?


235

我这样使用JQuery:

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

但是,看来,如果此人通过拖动窗口边缘以使其更大或更小来手动调整其浏览器窗口的大小,则.resize上面的事件会触发多次。

问题:浏览器窗口调整大小完成后如何调用函数(以便事件仅触发一次)?


请参阅以下答案:stackoverflow.com/questions/667426/…它涉及使用超时来延迟函数的执行。
Alastair Pitts 2010年

我不知道是否可行,您可以尝试通过benalman.com/projects/jquery-resize-plugin
BrunoLM 2010年

顺便说一句,我注意到这在移动浏览器中非常有用,这些浏览器在用户向下滚动时会逐渐隐藏地址栏,从而调整屏幕大小。我还希望屏幕调整大小仅在台式机上发生...
MakisH 2016年

Answers:


299

这是对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用于将所有超时事件分开。


2
我<3 u,我在调整全屏(非html5)Highcharts图形大小的同时结合了这一点,并且效果很好。
Michael J. Calkins

绝对不可思议!
Starkers 2014年

2
由于我从您的回答中受益匪浅,因此我想我为社区的其他成员共享了您提供的代码的工作原型:jsfiddle.net/h6h2pzpu/3。享受大家!
乔纳斯·斯托斯基

1
这是完美的,但是它将实际功能的执行延迟了毫秒(ms),这可能是非常不希望的。
Tomas M

这是否完美,是否有办法获取最后的调整大小而不必在这些毫秒上进行中继?无论如何,这只是节省了我的时间:')谢谢。
狮子座

138

我更喜欢创建一个事件:

$(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文件中。


我用了这个解决方案。但是从长远来看,我想实现与brahn解决方案相同的解决方案。
巴拉特·帕蒂尔

这使您可以绑定到整个事件,而不仅仅是在一个函数中进行绑定,当然
前提是

这对我不起作用,但DusanV回答完成了这项工作
lightbyte's

123

我使用以下函数来延迟重复的操作,它将适合您的情况:

var delay = (function(){
  var timer = 0;
  return function(callback, ms){
    clearTimeout (timer);
    timer = setTimeout(callback, ms);
  };
})();

用法:

$(window).resize(function() {
    delay(function(){
      alert('Resize...');
      //...
    }, 500);
});

传递给它的回调函数仅在指定的时间间隔后最后一次调用延迟时才执行,否则将重置计时器,我发现这对于其他目的很有用,例如检测用户何时停止键入等。 ..


5
我认为这种方法如果多次使用(例如,如果代码设置回调到的不同部分)可能会失败,$(window).resize因为它们将共享timer变量。请参阅下面的答案以获取建议的解决方案。
brahn 2010年

非常好!奇迹般有效!喜欢你的答案...简单而优雅!
南瓜先生2014年


20

某些先前提到的解决方案即使对我来说更通用,但对我却不起作用。另外,我发现这是在调整窗口大小的工作:

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

1
只有您的示例对我有用...上面的其他示例却没有!我不确定为什么未选择您的答案。
Mumbo Jumbo 2015年

我不明白为什么要在resize事件中捕获resize事件,但它也对我
有用

Mumbo Jumbo,我认为是因为其他人专注于泛化,正在寻找解决任何此类问题(函数的多次调用)的方法。
DusanV

lightbyte,这是因为每次调用该函数时都必须停止先前的事件。
DusanV '17

13

非常感谢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


6

实际上,据我所知,仅当您不知道未来用户的操作时,您才能在关闭调整大小后无法完全执行某些操作。但是您可以假设两个调整大小事件之间经过了时间,因此,如果您等待的时间超过此时间,并且没有进行任何调整大小,则可以调用函数。
想法是我们使用setTimeout及其ID来保存或删除它。例如,我们知道两个调整大小事件之间的时间为500毫秒,因此我们将等待750毫秒。

var a;
$(window).resize(function(){
  clearTimeout(a);
  a = setTimeout(function(){
    // call your function
  },750);
});


3

声明全局延迟的侦听器:

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

谢谢,这是目前最好的解决方案。我还测试了调整窗口大小时250ms的最佳工作方式。
AlexioVay


2

简单的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

    }

})();

1

假设在窗口调整大小后鼠标光标应返回到文档,我们可以使用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);
});

对于仅基于鼠标的台式机站点来说很好,但是例如,如果用户在移动设备上并从横向更改为纵向,或者如果他们在触摸屏桌面上调整窗口大小,则mouseover事件将永远不会发生。
user56reinstatemonica8 2013年

您可以借助最新窗口(例如Win-Arrow-Left Win-Arrow-Right等)上的键盘来调整浏览器窗口的大小...
Lu4 2015年

0

这是我实现的:

$(window).resize(function(){setTimeout(someFunction,500);});

如果我们希望调整大小小于以下时间,则可以清除setTimeout500ms

祝好运...

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.