JavaScript / JQuery: $ (window) .resize cara memecat SETELAH ukurannya selesai?

235

Saya menggunakan JQuery sebagai berikut:

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

Namun, tampaknya jika orang tersebut mengubah ukuran jendela browser secara manual dengan menyeret tepi jendela untuk membuatnya lebih besar / lebih kecil, .resizeacara di atas akan menyala beberapa kali.

Pertanyaan: Bagaimana saya memanggil fungsi SETELAH ukuran jendela browser selesai (sehingga acara hanya menyala sekali)?

sarah
sumber
Lihat jawaban ini: stackoverflow.com/questions/667426/… Ini melibatkan penggunaan timeout untuk menunda eksekusi fungsi Anda.
Alastair Pitts
Saya tidak tahu apakah itu mungkin, Anda dapat mencoba plugin ini melalui benalman.com/projects/jquery-resize-plugin
BrunoLM
Omong-omong, saya perhatikan ini sangat berguna di peramban seluler yang cenderung menyembunyikan bilah alamat secara bertahap ketika pengguna menggulir ke bawah, sehingga mengubah ukuran layar. Saya juga berharap ukuran layar hanya terjadi pada desktop ...
MakisH

Jawaban:

299

Berikut ini modifikasi solusi CMS yang dapat dipanggil di banyak tempat dalam kode Anda:

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

Pemakaian:

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

Solusi CMS baik-baik saja jika Anda hanya memanggilnya sekali, tetapi jika Anda menyebutnya berkali-kali, misalnya jika bagian kode Anda yang berbeda mengatur callback terpisah untuk mengubah ukuran jendela, maka itu akan gagal jika mereka berbagi timervariabel.

Dengan modifikasi ini, Anda memberikan id unik untuk setiap panggilan balik, dan ID unik tersebut digunakan untuk memisahkan semua acara timeout.

brahn
sumber
2
Saya <3 u, saya menggabungkan ini sambil mengubah ukuran grafik fullchart fullscreen (non html5) dan bekerja dengan baik.
Michael J. Calkins
Benar-benar luar biasa!
Starkers
2
Karena saya mendapat banyak manfaat dari jawaban Anda, saya pikir saya telah membagikan prototipe yang berfungsi dari kode yang Anda berikan kepada seluruh komunitas: jsfiddle.net/h6h2pzpu/3 . Selamat menikmati semuanya!
Jonas Stawski
1
Ini semua sempurna, TETAPI menunda eksekusi fungsi sebenarnya dengan jumlah milidetik (ms), yang mungkin SANGAT TIDAK DAPAT DIKIRIMKAN.
Tomas M
Ini hanya apakah itu sempurna? Apakah ada cara meraih ukuran terakhir dan tidak harus menyampaikan milidetik itu? Bagaimanapun ini baru saja menyelamatkan hariku: ') Terima kasih.
Leo
138

Saya lebih suka membuat acara:

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

Inilah cara Anda membuatnya:

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

Anda dapat memiliki ini di file javascript global di suatu tempat.

Carlos Martinez T
sumber
Saya menggunakan solusi ini. Tetapi dalam jangka panjang saya ingin menerapkan solusi yang sama dengan brahn.
Bharat Patil
ini memungkinkan Anda untuk mengikat acara itu di mana-mana, tidak hanya dalam satu fungsi, dengan asumsi Anda memiliki beberapa halaman / file .js yang memerlukan reaksi terpisah untuk itu tentu saja
hanzolo
Ini tidak berhasil untuk saya tetapi jawaban DusanV berhasil
lightbyte
123

Saya menggunakan fungsi berikut untuk menunda tindakan berulang, itu akan bekerja untuk kasus Anda:

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

Pemakaian:

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

Fungsi callback diteruskan, akan dijalankan hanya ketika panggilan terakhir untuk menunda telah dilakukan setelah jumlah waktu yang ditentukan, jika tidak timer akan diatur ulang, saya menemukan ini berguna untuk tujuan lain seperti mendeteksi ketika pengguna berhenti mengetik, dll. ..

CMS
sumber
5
Saya pikir pendekatan ini mungkin gagal jika digunakan beberapa kali (misalnya jika bagian berbeda dari kode pengaturan panggilan balik $(window).resize) karena mereka semua akan berbagi timervariabel. Lihat jawaban saya di bawah ini untuk solusi yang diusulkan.
brahn
Sangat bagus! Bekerja seperti pesona! Sukai jawaban Anda ... sederhana dan elegan!
Tn. Pumpkin
74

Jika Anda memiliki Underscore.js diinstal, Anda dapat:

$(window).resize(_.debounce(function(){
    alert("Resized");
},500));
JT.
sumber
1
Bahkan jika Anda tidak ingin menyertakan Underscore, setidaknya ambil sumber untuk ini: underscorejs.org/docs/underscore.html#section-67
tybro0103
Debounce adalah teknik yang benar di sini, itu hanya masalah implementasi. Dan ini adalah implementasi yang unggul jika Underscore / Lodash sudah menjadi ketergantungan proyek.
Factor Mystic
Inilah yang sekarang saya gunakan,
Bharat Patil
20

Beberapa solusi yang disebutkan sebelumnya tidak bekerja untuk saya, meskipun mereka lebih umum digunakan. Atau saya telah menemukan ini yang melakukan ukuran pada pekerjaan di jendela:

$(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);
    });
});
DusanV
sumber
1
Hanya teladan Anda yang bekerja untuk saya ... yang lain di atas tidak! Saya tidak yakin mengapa jawaban Anda tidak dipilih.
Mumbo Jumbo
Saya tidak mengerti mengapa menangkap acara pengubahan ukuran di dalam acara pengubahan ukuran, tetapi itu juga berfungsi untuk saya ...
lightbyte
Mumbo Jumbo, saya pikir karena orang lain fokus pada generalisasi, mencari solusi untuk masalah seperti itu (beberapa panggilan fungsi).
DusanV
lightbyte, itu karena Anda harus menghentikan acara sebelumnya setiap kali fungsi dipanggil.
DusanV
13

Terima kasih banyak kepada David Walsh, ini adalah versi vanilla dari garis bawah garis bawah.

Kode:

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

Penggunaan sederhana:

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

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

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

Irvin Dominin
sumber
6

Sebenarnya, seperti yang saya tahu, Anda tidak dapat melakukan beberapa tindakan tepat ketika mengubah ukuran mati, hanya karena Anda tidak tahu tindakan pengguna di masa depan. Tetapi Anda dapat mengasumsikan waktu berlalu antara dua peristiwa pengubahan ukuran, jadi jika Anda menunggu sedikit lebih dari waktu ini dan tidak ada pengubahan ukuran, Anda dapat memanggil fungsi Anda.
Ide adalah yang kami gunakan setTimeoutdan id untuk menyimpan atau menghapusnya. Misalnya kita tahu bahwa waktu antara dua peristiwa pengubahan ukuran adalah 500ms, oleh karena itu kami akan menunggu 750ms.

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

newint
sumber
3

Menyatakan pendengar yang tertunda secara global:

var resize_timeout;

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

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

Dan di bawah ini gunakan pendengar untuk resizedacara yang Anda inginkan:

$(window).on('resized', function(){
    console.log('resized');
});
gzzz
sumber
Terima kasih, itu adalah solusi terbaik saat ini. Saya juga telah menguji bahwa 250ms bekerja dengan cara terbaik ketika mengubah ukuran jendela.
AlexioVay
2

Plugin jQuery sederhana untuk acara pengubahan ukuran jendela yang tertunda.

SINTAKSIS:

Tambahkan fungsi baru untuk mengubah ukuran acara

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

Hapus fungsi (dengan mendeklarasikan ID-nya) yang ditambahkan sebelumnya

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

Hapus semua fungsi

jQuery(window).resizeDelayed( false );

PEMAKAIAN:

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

PENGGUNAAN OUTPUT:

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

PLUGIN:

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

    }

})();
Déján Kőŕdić
sumber
1

Dengan asumsi bahwa kursor mouse harus kembali ke dokumen setelah mengubah ukuran jendela, kita dapat membuat perilaku seperti panggilan balik dengan peristiwa onmouseover. Jangan lupa bahwa solusi ini mungkin tidak berfungsi untuk layar yang mendukung sentuhan seperti yang diharapkan.

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);
});
onur
sumber
Baik untuk situs berbasis desktop mouse saja tetapi acara mouseover tidak akan pernah terjadi jika, misalnya, pengguna menggunakan ponsel dan mengubah dari lanskap ke potret, atau jika mereka mengubah ukuran jendela pada desktop layar sentuh.
user56reinstatemonica8
Anda dapat mengubah ukuran jendela browser dengan bantuan keyboard di jendela terbaru seperti Win-Arrow-Left Win-Arrow-Right, dll ...
Lu4
0

Inilah yang saya terapkan:

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

kita dapat menghapus setTimeout jika kita berharap ukurannya terjadi kurang dari500ms

Semoga berhasil...

Akash
sumber