【问题标题】:JavaScript/JQuery: $(window).resize how to fire AFTER the resize is completed?JavaScript/JQuery: $(window).resize 调整大小完成后如何触发?
【发布时间】:2011-02-20 17:11:24
【问题描述】:

我正在使用 JQuery:

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

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

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

【问题讨论】:

  • 看到这个答案:stackoverflow.com/questions/667426/… 它涉及到使用超时来延迟你的函数的执行。
  • 我不知道这是否可能,你可以试试这个插件虽然benalman.com/projects/jquery-resize-plugin
  • 顺便说一句,我注意到这在移动浏览器中非常有用,当用户向下滚动时会逐渐隐藏地址栏,从而调整屏幕大小。我还希望屏幕调整大小只发生在桌面上...

标签: javascript jquery


【解决方案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
          }); 
          
          
          
           
          

          【讨论】:

            猜你喜欢
            • 2011-05-16
            • 1970-01-01
            • 2016-03-25
            • 2011-10-07
            • 1970-01-01
            • 1970-01-01
            • 2017-11-22
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多