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 调整大小完成后如何触发?的主要内容,如果未能解决你的问题,请参考以下文章

wind能帮忙加工数据吗

POJ 2763 Housewife Wind

详谈Wind8系统改为Wind7操作步骤

javascript/jQuery - 啥是 jQuery.fx?

JavaFX,NASA World Wind:如何将 JavaFX 组添加到 NASA World Wind Model

javascript 使用JQuery #javascript #jquery将“a”tages滚动到div ID