web-dev-qa-db-fra.com

JavaScript/JQuery: $ (window) .resize comment se déclencher APRES la fin du redimensionnement

J'utilise JQuery en tant que tel:

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

Cependant, il semble que si la personne redimensionne manuellement les fenêtres de son navigateur en faisant glisser la fenêtre Edge pour la rendre plus grande/plus petite, l'événement .resize ci-dessus se déclenche plusieurs fois.

Question: Comment appeler une fonction APRÈS le redimensionnement de la fenêtre du navigateur terminé (afin que l'événement ne se déclenche qu'une seule fois)?

220
sarah

Voici une modification de la solution CMS qui peut être appelée à plusieurs endroits dans votre code:

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

Usage:

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

La solution de CMS est acceptable si vous l’appelez une seule fois, mais si vous l’appelez plusieurs fois, par exemple. si différentes parties de votre code configurent des rappels distincts pour le redimensionnement de la fenêtre, il échouera car ils partagent la variable timer

Avec cette modification, vous fournissez un identifiant unique pour chaque rappel, et ces identifiants uniques sont utilisés pour conserver tous les événements de délai d'attente séparés.

295
brahn

Je préfère créer un événement:

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

Voici comment vous le créez:

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

Vous pourriez avoir cela dans un fichier JavaScript global quelque part.

132

J'utilise la fonction suivante pour retarder les actions répétées, cela fonctionnera pour votre cas:

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

Usage:

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

La fonction de rappel qui lui est transmise ne sera exécutée que lorsque le dernier appel à retarder aura été passé après le délai spécifié. Sinon, un chronomètre sera réinitialisé. Je trouve cela utile pour d'autres raisons, telles que la détection du moment où l'utilisateur arrête de taper, etc. ..

121
CMS

Si vous avez Underscore.js installé, vous pouvez:

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

Certaines des solutions mentionnées précédemment ne fonctionnaient pas pour moi, même si leur usage était plus général. Alternativement j'ai trouvé celui-ci qui a fait le travail sur la fenêtre redimensionner:

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

Un grand merci à David Walsh, voici une version vanille de underscore debounce.

Code:

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

Utilisation simple:

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

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

Réf: http://davidwalsh.name/javascript-debounce-function

11
Irvin Dominin

En fait, comme je le sais, vous ne pouvez pas effectuer certaines actions exactement lorsque le redimensionnement est désactivé, simplement parce que vous ne connaissez pas les actions des futurs utilisateurs. Mais vous pouvez supposer que le temps s'est écoulé entre deux événements de redimensionnement. Si vous attendez un peu plus longtemps et qu'aucun redimensionnement n'est effectué, vous pouvez appeler votre fonction.
L’idée est que nous utilisons setTimeout et son identifiant afin de le sauvegarder ou de le supprimer. Par exemple, nous savons que le temps entre deux événements de redimensionnement est de 500 ms. Par conséquent, nous attendrons 750 ms.

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

6
newint

Déclarez un auditeur globalement différé:

var resize_timeout;

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

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

Et ci-dessous, utilisez les écouteurs pour resized événements comme vous le souhaitez:

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

Simple plugin jQuery pour un événement de redimensionnement de fenêtre retardé.

SYNTAXE:

Ajouter une nouvelle fonction pour redimensionner un événement

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

Supprime la fonction (en déclarant son ID) ajoutée précédemment

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

Supprimer toutes les fonctions

jQuery(window).resizeDelayed( false );

USAGE:

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

SORTIE D'UTILISATION:

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

BRANCHER:

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

    }

})();
2

En supposant que le curseur de la souris retourne au document après le redimensionnement de la fenêtre, nous pouvons créer un comportement semblable à un rappel avec l'événement onmouseover. N'oubliez pas que cette solution peut ne pas fonctionner correctement avec les écrans tactiles.

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

Ça marche pour moi. Voir cette solution - https://alvarotrigo.com/blog/firing-resize-event-only-once-when-resizing-is-finished/

var resizeId;
$(window).resize(function() {
    clearTimeout(resizeId);
    resizeId = setTimeout(doneResizing, 500);
});
function doneResizing(){
    //whatever we want to do 
}

1
vishwa

Voici ce que j'ai implémenté:

$ (fenêtre) .resize (fonction () { setTimeout (someFunction, 500); });

nous pouvons définir [clear the setTimeout][1] si nous prévoyons un redimensionnement inférieur à 500ms 

Bonne chance...

0
Akash