JavaScript / JQuery: $ (finestra) .resize come attivare DOPO che il ridimensionamento sia completato?


235

Sto usando JQuery come tale:

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

Tuttavia, sembra che se la persona ridimensiona manualmente le finestre del browser trascinando il bordo della finestra per renderlo più grande / più piccolo, l' .resizeevento sopra si attiva più volte.

Domanda: Come chiamare una funzione DOPO che il ridimensionamento della finestra del browser è stato completato (in modo che l'evento si attivi solo una volta)?


Vedi questa risposta: stackoverflow.com/questions/667426/… Comporta l'uso di timeout per ritardare l'esecuzione della tua funzione.
Alastair Pitts,

Non so se sia possibile, potresti provare questo plugin anche se benalman.com/projects/jquery-resize-plugin
BrunoLM,

A proposito, ho notato che questo è molto utile nei browser mobili che tendono a nascondere gradualmente la barra degli indirizzi quando l'utente scorre verso il basso, ridimensionando quindi lo schermo. Mi aspettavo anche che il ridimensionamento dello schermo avvenisse solo sul desktop ...
MakisH,

Risposte:


299

Ecco una modifica della soluzione di CMS che può essere chiamata in più punti del codice:

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

Uso:

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

La soluzione di CMS va bene se la chiami una volta sola, ma se la chiami più volte, ad es. Se parti diverse del tuo codice impostano callback separate per il ridimensionamento della finestra, allora fallirà perché condividono la timervariabile.

Con questa modifica, viene fornito un ID univoco per ciascun callback e tali ID univoci vengono utilizzati per mantenere separati tutti gli eventi di timeout.


2
I <3 u, l'ho combinato durante il ridimensionamento dei grafici Highcharts a schermo intero (non html5) e funziona alla grande.
Michael J. Calkins,

Assolutamente incredibile!
Starkers,

2
Dato che ho beneficiato moltissimo della tua risposta, ho pensato di condividere un prototipo funzionante del tuo codice fornito per il resto della comunità: jsfiddle.net/h6h2pzpu/3 . Buon divertimento a tutti!
Jonas Stawski,

1
Tutto è perfetto, MA ritarda l'esecuzione della funzione effettiva della quantità di millisecondi (ms), che può essere MOLTO INDESIDERABILE.
Tomas M,

Questo lo fa semplicemente, c'è un modo per afferrare l'ultimo ridimensionamento e non dover ricorrere a quei millisecondi? Comunque questo mi ha appena salvato la giornata: ') Grazie.
Leone

138

Preferisco creare un evento:

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

Ecco come lo crei:

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

Potresti avere questo in un file javascript globale da qualche parte.


Ho usato questa soluzione. Ma a lungo termine vorrei implementare la stessa soluzione di Brahn.
Bharat Patil,

questo ti permette di legarti a quell'evento dappertutto, non solo in una funzione, supponendo che tu abbia più pagine / file .js che richiedono reazioni separate ad esso ovviamente
hanzolo

Questo non ha funzionato per me, ma DusanV risposta ha fatto il lavoro
lightbyte

123

Uso la seguente funzione per ritardare le azioni ripetute, funzionerà per il tuo caso:

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

Uso:

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

La funzione di callback passata ad esso, verrà eseguita solo quando l'ultima chiamata al ritardo è stata effettuata dopo il periodo di tempo specificato, altrimenti verrà ripristinato un timer, lo trovo utile per altri scopi come rilevare quando l'utente ha smesso di digitare, ecc. ..


5
Penso che questo approccio potrebbe fallire se usato più volte (ad es. Se parti diverse dei callback di impostazione del codice $(window).resize) perché condivideranno tutti la timervariabile. Vedi la mia risposta di seguito per la soluzione proposta.
brahn,

Molto bella! Funziona come un fascino! Metti mi piace alle tue risposte ... semplice ed elegante!
Mr. Pumpkin,

74

Se hai installato Underscore.js, potresti:

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

1
Anche se non vuoi includere Underscore, almeno prendi la fonte per questo: underscorejs.org/docs/underscore.html#section-67
tybro0103

Debounce è la tecnica corretta qui, è solo una questione di implementazioni. E questa è un'implementazione superiore se Underscore / Lodash è già una dipendenza dal progetto.
Factor Mystic,

Questo è quello che sto usando,
Bharat Patil,

20

Alcune delle soluzioni precedentemente menzionate non hanno funzionato per me, anche se sono di uso più generale. In alternativa ho trovato questo che ha fatto il lavoro sul ridimensionamento della finestra:

$(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
Solo il tuo esempio ha funzionato per me ... gli altri sopra no! Non sono sicuro del motivo per cui la tua risposta non è stata selezionata.
Mumbo Jumbo,

Non capisco perché catturare l'evento di ridimensionamento all'interno dell'evento di ridimensionamento, ma funziona anche per me ...
lightbyte

Mumbo Jumbo, penso perché gli altri si concentrano sulla generalizzazione, cercando una soluzione a tale problema (chiamate multiple di una funzione).
DusanV,

lightbyte, è perché devi interrompere eventi precedenti ogni volta che viene chiamata la funzione.
DusanV,

13

Mille grazie a David Walsh, ecco una versione vaniglia del carattere di sottolineatura.

Codice:

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

Semplice utilizzo:

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

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

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


6

In realtà, come so, non è possibile eseguire alcune azioni esattamente quando il ridimensionamento è disattivato, semplicemente perché non si conoscono le azioni dell'utente futuro. Ma puoi presumere il tempo trascorso tra due eventi di ridimensionamento, quindi se aspetti un po 'più di questo tempo e non viene effettuato alcun ridimensionamento, puoi chiamare la tua funzione.
L'idea è che usiamo setTimeouted è id per salvarlo o eliminarlo. Ad esempio sappiamo che il tempo tra due eventi di ridimensionamento è di 500 ms, quindi aspetteremo 750 ms.

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


3

Dichiarare ascoltatore ritardato a livello globale:

var resize_timeout;

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

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

E di seguito usa i listener per l' resizedevento come vuoi:

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

Grazie, questa è la migliore soluzione al momento. Inoltre ho testato che 250ms funziona nel modo migliore quando si ridimensiona la finestra.
AlexioVay


2

Semplice plug-in jQuery per evento di ridimensionamento della finestra ritardato.

SINTASSI:

Aggiungi una nuova funzione per ridimensionare l'evento

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

Rimuovere la funzione (dichiarandone l'ID) aggiunta in precedenza

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

Rimuovi tutte le funzioni

jQuery(window).resizeDelayed( false );

USO:

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

USCITA DI UTILIZZO:

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

COLLEGARE:

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

Supponendo che il cursore del mouse debba tornare al documento dopo il ridimensionamento della finestra, possiamo creare un comportamento simile alla richiamata con l'evento onmouseover. Non dimenticare che questa soluzione potrebbe non funzionare per gli schermi abilitati al tocco come previsto.

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

Va bene per siti solo desktop basati su mouse, ma l'evento del mouseover non accadrà mai se, ad esempio, l'utente è su un dispositivo mobile e passa da orizzontale a verticale o se ha ridimensionato la finestra su un desktop touchscreen.
user56reinstatemonica8

Puoi ridimensionare la finestra del browser con l'aiuto della tastiera sugli ultimi file di Windows come Win-Arrow-Left Win-Arrow-Right, ecc ...
Lu4

0

Questo è quello che ho implementato:

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

possiamo cancellare setTimeout se prevediamo che il ridimensionamento accada meno di500ms

In bocca al lupo...

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.