JavaScript / JQuery: $ (pencere). Yeniden boyutlandırma tamamlandıktan SONRA nasıl tetiklenir?


235

JQuery gibi kullanıyorum:

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

Ancak, kişi tarayıcı pencerelerini büyütmek / küçültmek için pencere kenarını sürükleyerek manuel olarak yeniden boyutlandırırsa, .resizeyukarıdaki etkinlik birden çok kez tetiklenir.

Soru: Tarayıcı penceresinin yeniden boyutlandırılmasından SONRA bir işlevi nasıl arayabilirim (böylece etkinlik yalnızca bir kez tetiklenir)?


Şu yanıta bakın: stackoverflow.com/questions/667426/… İşlevinizin yürütülmesini geciktirmek için zaman aşımlarının kullanılmasını içerir.
Alastair Pitts

Ben bu mümkünse olsa, bu eklentiyi deneyebilirsiniz bilmiyorum benalman.com/projects/jquery-resize-plugin
BrunoLM

Bu arada, kullanıcının aşağı kaydırdığında adres çubuğunu kademeli olarak gizleme eğiliminde olan ve bu nedenle ekranı yeniden boyutlandıran mobil tarayıcılarda çok yararlı olduğunu fark ettim. Ayrıca ekran yeniden boyutlandırma sadece masaüstünde gerçekleşmesini
bekledim

Yanıtlar:


299

Kodunuzda birden çok yerde çağrılabilecek bir CMS çözümünün değiştirilmesi:

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

Kullanımı:

$(window).resize(function () {
    waitForFinalEvent(function(){
      alert('Resize...');
      //...
    }, 500, "some unique string");
});

CMS'nin çözümü yalnızca bir kez çağırırsanız iyi olur, ancak birden çok kez çağırırsanız, örneğin kodunuzun farklı bölümleri pencere yeniden boyutlandırması için ayrı geri aramalar ayarladıysa, timerdeğişkeni paylaştıklarında başarısız olur .

Bu değişiklikle, her geri arama için benzersiz bir kimlik sağlarsınız ve bu benzersiz kimlikler, tüm zaman aşımı olaylarını ayrı tutmak için kullanılır.


2
Ben <3 u, ben tam ekran yeniden boyutlandırırken (html5 olmayan) Highcharts grafikler birleştirdi ve harika çalışıyor.
Michael J.Calkins

Kesinlikle inanılmaz!
Starkers

2
Cevabınızdan çok yararlandığım için, topluluğun geri kalanı için sağlanan kodunuzun çalışan bir prototipini paylaştığımı düşündüm: jsfiddle.net/h6h2pzpu/3 . Herkesin tadını çıkarın!
Jonas Stawski

1
Bu mükemmel, AMA gerçek fonksiyonun yürütülmesini ÇOK İSTENMEYEN milisaniye (ms) kadar geciktirir.
Tomas M

Bu sadece son yeniden boyutlandırma kapmak ve bu milisaniye geçiş yapmak zorunda değil mi? Her neyse, bu benim günümü kurtardı: ') Teşekkürler.
Leo

138

Bir etkinlik oluşturmayı tercih ediyorum:

$(window).bind('resizeEnd', function() {
    //do something, window hasn't changed size in 500ms
});

Nasıl oluşturduğunuz aşağıda açıklanmıştır:

 $(window).resize(function() {
        if(this.resizeTO) clearTimeout(this.resizeTO);
        this.resizeTO = setTimeout(function() {
            $(this).trigger('resizeEnd');
        }, 500);
    });

Bunu bir yerlerde global bir javascript dosyasında bulabilirsiniz.


Bu çözümü kullandım. Fakat uzun vadede brahn'ın çözümü ile aynı şeyi uygulamak istiyorum.
Bharat Patil

bu, tek bir işlevle değil, aynı etkinliğe ayrı tepkiler gerektiren birden fazla sayfa / .js dosyanız olduğunu varsayarak, o etkinliğe her yerde bağlanmanıza izin verir
hanzolo 8:14

Bu benim için işe yaramadı ama DusanV cevabı işi yaptı
lightbyte

123

Tekrarlanan eylemleri geciktirmek için aşağıdaki işlevi kullanıyorum, durumunuz için çalışacaktır:

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

Kullanımı:

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

Ona iletilen geri arama işlevi, yalnızca belirtilen süreden sonra son gecikme çağrısı yapıldığında yürütülür, aksi takdirde bir zamanlayıcı sıfırlanır, bunu kullanıcının yazmayı durdurduğunda algılama gibi diğer amaçlar için yararlı buluyorum. ..


5
Ben $(window).resizetüm timerdeğişken paylaşacak çünkü bu yaklaşım birden çok kez (örneğin kod kurulumu geri çağrıları farklı bölümleri için ) kullanılırsa başarısız olabilir düşünüyorum . Önerilen çözüm için aşağıdaki cevabıma bakın.
brahn

Çok hoş! Tıkır tıkır çalışıyor! Cevaplarınız gibi ... basit ve zarif!
Bay Pumpkin

74

Eğer sen Underscore.js yüklü, aşağıdakileri yapabilirsiniz:

$(window).resize(_.debounce(function(){
    alert("Resized");
},500));


Debounce burada doğru teknik, sadece bir uygulama meselesi. Ve bu, Undercore / Lodash zaten bir proje bağımlılığı ise üstün uygulama.
Faktör Mistik

Şu an kullandığım şey bu,
Bharat Patil

20

Daha genel olarak kullanılsalar da, daha önce bahsedilen çözümlerin bazıları benim için işe yaramadı. Alternatif olarak , pencere yeniden boyutlandırma iş yaptı bu bir buldum :

$(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
Sadece örneğiniz benim için çalıştı ... yukarıdaki diğerleri işe yaramadı! Cevabınızın neden seçilmediğinden emin değilim.
Mumbo Jumbo


Mumbo Jumbo, sanırım çünkü diğerleri genellemeye odaklanıyor, böyle bir soruna çözüm arıyorlar (bir fonksiyonun çoklu çağrıları).
DusanV

lightbyte, çünkü fonksiyon her çağrıldığında önceki olayları durdurmanız gerekir.
DusanV

13

David Walsh'a çok teşekkürler, burada alt çizginin açılmasının vanilya versiyonu var.

Kod:

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

Basit kullanım:

var myEfficientFn = debounce(function() {
    // All the taxing stuff you do
}, 250);

$(window).on('resize', myEfficientFn);

Ref: http://davidwalsh.name/javascript-debounce-function


6

Aslında, bildiğim gibi, yeniden boyutlandırma kapalıyken bazı eylemleri tam olarak yapamazsınız, çünkü gelecekteki kullanıcının eylemlerini bilmiyorsunuzdur. Ancak iki yeniden boyutlandırma olayı arasında geçen süreyi varsayabilirsiniz, bu nedenle bu süreden biraz daha fazla beklerseniz ve yeniden boyutlandırma yapılmazsa, işlevinizi çağırabilirsiniz.
Fikir, kullanmak setTimeoutve kaydetmek veya silmek için kimliği olmasıdır. Örneğin, iki yeniden boyutlandırma olayı arasındaki sürenin 500 ms olduğunu biliyoruz, bu nedenle 750 ms bekleyeceğiz.

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


3

Küresel olarak gecikmiş dinleyici bildir:

var resize_timeout;

$(window).on('resize orientationchange', function(){
    clearTimeout(resize_timeout);

    resize_timeout = setTimeout(function(){
        $(window).trigger('resized');
    }, 250);
});

Ve aşağıda dinleyicileri istediğiniz resizedetkinlik için kullanın :

$(window).on('resized', function(){
    console.log('resized');
});

Teşekkürler, şu anda en iyi çözüm bu. Ayrıca pencereyi yeniden boyutlandırırken 250ms'in en iyi şekilde çalıştığını test ettim.
AlexioVay


2

Gecikmeli pencere yeniden boyutlandırma olayı için basit jQuery eklentisi.

SÖZDİZİMİ:

Etkinliği yeniden boyutlandırmak için yeni işlev ekle

jQuery(window).resizeDelayed( func, delay, id ); // delay and id are optional

Daha önce eklenen işlevi (kimliğini bildirerek) kaldırın

jQuery(window).resizeDelayed( false, id );

Tüm işlevleri kaldır

jQuery(window).resizeDelayed( false );

KULLANIM:

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

KULLANIM ÇIKIŞI:

first event - should run after 0.4 seconds
newest event - should run after 0.5 second
third event - should run after 3.0 seconds

EKLENTİ:

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

Fare imlecinin pencere yeniden boyutlandırıldıktan sonra belgeye geri dönmesi gerektiğini varsayarsak, aşırı olayla geri arama benzeri bir davranış oluşturabiliriz. Bu çözümün dokunmatik ekranlarda beklendiği gibi çalışmayabileceğini unutmayın.

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

Yalnızca fare tabanlı masaüstü siteleri için uygundur, ancak örneğin bir mobil cihazdaysa ve yataydan dikey konuma değişirse veya pencereyi dokunmatik ekranlı bir masaüstünde yeniden boyutlandırırsa fareyle üzerine gelme etkinliği hiçbir zaman gerçekleşmez.
user56reinstatemonica8

Win-Arrow-Left Win-Arrow-Right, vb.Gibi en son pencerelerde klavye yardımıyla tarayıcı penceresini yeniden boyutlandırabilirsiniz ...
Lu4

0

Ben uyguladık budur:

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

Biz yapabilirsiniz setTimeout temizlemek biz boyutlandırmak az olmasını bekliyorsanız500ms

İyi şanslar...

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.