JQuery:如何仅在完成调整大小后才调用 RESIZE 事件?

Posted

技术标签:

【中文标题】JQuery:如何仅在完成调整大小后才调用 RESIZE 事件?【英文标题】:JQuery: How to call RESIZE event only once it's FINISHED resizing? 【发布时间】:2011-05-16 23:08:49 【问题描述】:

浏览器窗口完成调整大小后如何调用函数?

我正在尝试这样做,但遇到了问题。我正在使用 JQuery Resize 事件函数:

$(window).resize(function() 
  ... // how to call only once the browser has FINISHED resizing?
);

但是,如果用户手动调整浏览器窗口的大小,则连续调用此函数。也就是说,它可能会在很短的时间内调用这个函数几十次。

我怎样才能只调用一次调整大小函数一次(一旦浏览器窗口完成调整大小)?

更新

也不必使用全局变量。

【问题讨论】:

@BGerrissen,如果你能告诉我如何在没有全局变量的情况下使用jsfiddle.net/Zevan/c9UE5/1,我一定会的 :) 上面的 cleartimeout/settimeout 方法效果很好。 javascript/JQuery: $(window).resize how to fire AFTER the resize is completed?的可能重复 【参考方案1】:

Here is an example using thejh's instructions

您可以将参考 id 存储到任何 setInterval 或 setTimeout。像这样:

var loop = setInterval(func, 30);

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

【讨论】:

我喜欢这段代码如此简单。有什么方法可以使这项工作不必使用全局变量? 如果我知道如何在没有全局变量的情况下执行此操作,我会将其设为“已接受的答案” 没问题。有几种方法。我已经编辑了答案以反映我能想到的最简单的答案。 感谢更新,但它似乎仍在使用全局变量。您可以将其更新为不需要全局变量(var id)。谢谢 我认为您错过了帖子末尾的链接...检查一下:jsfiddle.net/Zevan/c9UE5/5【参考方案2】:

Debounce.

function debouncer( func , timeout ) 
   var timeoutID , timeout = timeout || 200;
   return function () 
      var scope = this , args = arguments;
      clearTimeout( timeoutID );
      timeoutID = setTimeout( function () 
          func.apply( scope , Array.prototype.slice.call( args ) );
       , timeout );
   



$( window ).resize( debouncer( function ( e ) 
    // do stuff 
 ) );

注意,您可以将此方法用于任何您想要去抖动的东西(关键事件等)。

调整超时参数以获得最佳预期效果。

【讨论】:

我刚刚尝试运行它,它似乎运行 TWICE。我用 "$("body").append("DONE!");" 替换了 "// do stuff" 并且它两次调用它浏览器调整大小 oops...我忘记了一个相当重要的部分(实际上是设置 timeoutID)...现在已修复,请重试;) @user43493:它调用函数func,内部this指针指向scopeArray.prototype.slice.call(args)(从args生成标准数组)为论据 这是一个可重用的抽象,因此您不必手动编码超时或自己跟踪全局 timeoutID。您可以将它用于更多的方式,而不仅仅是调整窗口大小;)例如,通过传递更高的超时参数来消除提交按钮的抖动。您可以选择代码更少的解决方案,但我建议您将这个 sn-p 保留在您的工具包中,稍后您会喜欢它的;) 如果您已经在使用该库,Underscore.js 有一个很好的实现。 underscorejs.org/#debounce【参考方案3】:

您可以将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)-event-handler。如果在给定的时间间隔内未触发事件,它会将一个或多个事件的事件处理函数附加到所选元素。如果您只想在延迟后触发回调,这很有用,例如调整大小事件,或者其他。 https://github.com/yckart/jquery.unevent.js

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

像任何其他 onbind-event 处理程序一样使用它,除了你可以传递一个额外的参数作为最后一个:

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

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

【讨论】:

每天都做同样的谷歌搜索。并为这段代码来到同一页面。希望我能记住它哈哈。【参考方案4】:
var lightbox_resize = false;
$(window).resize(function() 
    console.log(true);
    if (lightbox_resize)
        clearTimeout(lightbox_resize);
    lightbox_resize = setTimeout(function() 
        console.log('resize');
    , 500);
);

【讨论】:

我最喜欢这个,但为什么不在你的条件语句中使用大括号呢?我知道没有它们也能正常工作,但其他开发人员看着很痛苦 ;)【参考方案5】:

补充一下,由于滚动条弹出和弹出,通常会收到不需要的调整大小事件,这里有一些代码可以避免这种情况:

function registerResize(f) 
    $(window).resize(function() 
        clearTimeout(this.resizeTimeout);
        this.resizeTimeout = setTimeout(function() 
            var oldOverflow = document.body.style.overflow;
            document.body.style.overflow = "hidden";
            var currHeight = $(window).height(),
                currWidth = $(window).width();
            document.body.style.overflow = oldOverflow;

            var prevUndefined = (typeof this.prevHeight === 'undefined' || typeof this.prevWidth === 'undefined');
            if (prevUndefined || this.prevHeight !== currHeight || this.prevWidth !== currWidth) 
                //console.log('Window size ' + (prevUndefined ? '' : this.prevHeight + "," + this.prevWidth) + " -> " + currHeight + "," + currWidth);
                this.prevHeight = currHeight;
                this.prevWidth = currWidth;

                f(currHeight, currWidth);
            
        , 200);
    );
    $(window).resize(); // initialize


registerResize(function(height, width) 
    // this will be called only once per resize regardless of scrollbars changes
);

见jsfiddle

【讨论】:

【参考方案6】:

Underscore.js 有几个很好的方法来完成这个任务:throttledebounce。即使您不使用下划线,也请查看这些函数的来源。这是一个例子:

var redraw = function() 'redraw logic here';
var debouncedRedraw = _.debounce(redraw, 750);
$(window).on('resize', debouncedRedraw);

【讨论】:

【参考方案7】:

这是我的方法:

document.addEventListener('DOMContentLoaded', function()
    var tos = ;
    var idi = 0;
    var fn  = function(id)
    
        var len = Object.keys(tos).length;

        if(len == 0)
            return;

        to = tos[id];
        delete tos[id];

        if(len-1 == 0)
            console.log('Resize finished trigger');
    ;

    window.addEventListener('resize', function()
        idi++;
        var id = 'id-'+idi;
        tos[id] = window.setTimeout(function()fn(id), 500);
    );
);

resize-event-listener 捕获所有传入的 resize 调用,为每个调用创建一个超时函数,并将超时标识符与 'id-' 前面的迭代数字一起保存在 @987654323 中(可用作数组键) @-数组。

每次触发 timout 时,它都会调用 fn 函数,该函数会检查是否是 tos 数组中的最后一次超时(fn 函数会删除每个执行的 timout)。如果为 true (= if(len-1 == 0)),则调整大小完成。

【讨论】:

如果你有一些 cmets 或关于你在这里做什么的解释会很好【参考方案8】:

jQuery 提供了一个off 方法来移除事件处理程序

$(window).resize(function()
    if(magic == true) 
        $(window).off('resize', arguments.callee);
    
);

【讨论】:

以上是关于JQuery:如何仅在完成调整大小后才调用 RESIZE 事件?的主要内容,如果未能解决你的问题,请参考以下文章

图像控制 ActualWidth 仅在第二次加载后才正确 - Image Cropper

仅在每个项目完成其方法调用后才返回

仅在 javascript 循环完成后执行 ajax 调用

如何配置 jQuery.Lazy() 插件仅在加载第一个元素后才加载第二个元素

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

如何等到吐司完成?仅在 toast 隐藏 prev 测试后才开始第二次测试