JQuery: RESIZE olayı yalnızca FINISHED yeniden boyutlandırıldığında nasıl çağrılır?


109

Tarayıcı pencereleri FINISHED yeniden boyutlandırıldıktan sonra bir işlevi nasıl çağırırım?

Öyle yapmaya çalışıyorum ama sorunlar yaşıyorum. JQuery Resize olay işlevini kullanıyorum:

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

Ancak, kullanıcı tarayıcı penceresini manuel olarak yeniden boyutlandırıyorsa bu işlev sürekli olarak çağrılır . Yani bu işlevi kısa zaman aralıklarında onlarca kez çağırabilir.

Yeniden boyutlandırma işlevini yalnızca bir kez nasıl çağırabilirim (tarayıcı penceresi yeniden boyutlandırmayı bitirdiğinde)?

GÜNCELLEME

Ayrıca global bir değişken kullanmak zorunda kalmadan.


@BGerrissen, global bir değişken olmadan jsfiddle.net/Zevan/c9UE5/1 nasıl yapılacağını bana gösterebilirseniz , kesinlikle yapacağım :)
nickb

yukarıdaki cleartimeout / settimeout yöntemi harika bir şekilde çalışıyor.
kris-o3

Yanıtlar:


129

İşte jh'nin talimatlarını kullanan bir örnek

Herhangi bir setInterval veya setTimeout için bir referans kimliği saklayabilirsiniz. Bunun gibi:

var loop = setInterval(func, 30);

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

Bu kodun bu kadar basit olmasını seviyorum. Global bir değişken kullanmak zorunda kalmadan bunu yapmanın bir yolu var mı?
nickb

Bunu global değişken olmadan nasıl yapacağımı görürsem, bunu "kabul edilen cevap"
yapacağım

sorun değil. Birkaç yol var. Cevabı, aklıma gelen en basit olanı yansıtacak şekilde düzenledim.
Zevan

güncelleme için teşekkürler, ancak yine de genel bir değişken kullanıyor gibi görünüyor. Global bir değişken (var id) gerektirmeyecek şekilde güncelleyebilir misiniz? Teşekkürler
nickb

4
Sanırım gönderinin sonundaki bağlantıyı kaçırdınız ... kontrol edin: jsfiddle.net/Zevan/c9UE5/5
Zevan

85

Geri çekil .

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

Bu yöntemi geri almak istediğiniz herhangi bir şey için kullanabilirsiniz (önemli olaylar vb.).

İstenilen optimum etki için zaman aşımı parametresini ayarlayın.


1
Bunu çalıştırmayı denedim ve TWICE çalıştırıyor gibi görünüyor . Ben yerini "// şeyler" ile "$ (" body ") (BİTTİ <br/>!") Append. ";" ve tarayıcı yeniden boyutlandırmada TWICE diyor
nickb

oops ... Oldukça önemli bir kısmı unuttum (aslında zaman
aşımı kimliğini

3
@ user43493: funcDahili thisişaretçi işaret ederek ve argümanlar olarak (standart bir dizi oluşturan) scopeile cuntion'u çağırırArray.prototype.slice.call(args)args
Eric

4
Bu yeniden kullanılabilir bir soyutlamadır, bu nedenle zaman aşımlarını elle kodlamanız veya genel zaman aşımı kimliğini kendiniz takip etmeniz gerekmez. Bunu, pencereyi yeniden boyutlandırmaktan çok daha fazlası için kullanabilirsiniz;) örneğin, daha yüksek bir zaman aşımı parametresi geçirerek bir gönderme düğmesini geri almak için. Daha az kod çözümünü tercih edebilirsiniz, ancak bu pasajı kitinizde saklamanızı tavsiye ederim, daha sonra takdir edeceksiniz;)
BGerrissen

2
Underscore.js, bu lib'yi zaten kullanıyorsanız bunun güzel bir uygulaması vardır. underscorejs.org/#debounce
twmulloy

22

setTimeout()Ve kullanabilirsinizclearTimeout() birlikte jQuery.data:

$(window).resize(function() {
    clearTimeout($.data(this, 'resizeTimer'));
    $.data(this, 'resizeTimer', setTimeout(function() {
        //do something
        alert("Haven't resized in 200ms!");
    }, 200));
});

Güncelleme

JQuery'nin varsayılan (& ) -event-işleyicisini geliştirmek için bir uzantı yazdım . Olay belirli bir aralık için tetiklenmemişse, seçilen öğelere bir veya daha fazla olay için bir olay işleyici işlevi ekler. Bu, bir geri aramayı yalnızca yeniden boyutlandırma etkinliği veya başka bir gecikmeden sonra tetiklemek istiyorsanız kullanışlıdır. https://github.com/yckart/jquery.unevent.jsonbind

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

Diğerleri gibi kullanın onbindSon olarak fazladan bir parametre iletebilmeniz dışında, veya olay işleyicisi :

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

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


1
Kelimenin tam anlamıyla her gün aynı google aramasını yapın. ve bu kod parçası için aynı sayfaya gelin. Keşke sadece hatırlayabilseydim haha.
Dustin İpek

7
var lightbox_resize = false;
$(window).resize(function() {
    console.log(true);
    if (lightbox_resize)
        clearTimeout(lightbox_resize);
    lightbox_resize = setTimeout(function() {
        console.log('resize');
    }, 500);
});

Bunu en çok seviyorum ama neden koşullu ifadelerinizde küme parantezleri kullanmıyorsunuz? Onlar olmadan çalıştığını biliyorum ama diğer geliştiriciler için de bir acı;)
teewuane

7

Yukarıdakilere eklemek için, kaydırma çubuklarının içeri ve dışarı fırlaması nedeniyle istenmeyen yeniden boyutlandırma olayları almak yaygındır, işte bundan kaçınmak için bazı kodlar:

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'a bakın


5

Underscore.js , bu görev için birkaç harika yönteme sahiptir: throttleve debounce. Alt Çizgi kullanmıyor olsanız bile, bu işlevlerin kaynağına bir göz atın. İşte bir örnek:

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

2

Bu benim yaklaşımım:

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, gelen tüm yeniden boyutlandırma çağrılarını yakalar, her biri için bir zaman aşımı işlevi oluşturur ve zaman aşımı tanımlayıcısını, başına 'id-'(dizi anahtarı olarak kullanılabilir) eklenmiş bir yineleme numarasıyla birlikte kaydeder .tos -dizide ( eklenen .

zaman aşımı her tetiklendiğinde, dizideki fnson zaman aşımı olup olmadığını kontrol eden- işlevi çağırır tos(fn işlevi yürütülen her zaman aşımını siler). true (= if(len-1 == 0)) ise, yeniden boyutlandırma tamamlanır.


Burada ne yaptığınıza dair bazı yorumlarınız veya açıklamanız olsaydı çok iyi olurdu
Brett Gregson

1

jQuery, offolay işleyicisini kaldırmak için bir yöntem sağlar

$(window).resize(function(){
    if(magic == true) {
        $(window).off('resize', arguments.callee);
    }
});
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.