JavaScript / JQuery: $ (Fenster) .resize Wie wird ausgelöst, nachdem die Größenänderung abgeschlossen ist?

235

Ich verwende JQuery als solches:

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

Es scheint jedoch, dass das obige .resizeEreignis mehrmals ausgelöst wird, wenn die Person ihre Browserfenster manuell durch Ziehen der Fensterkante ändert, um sie größer / kleiner zu machen .

Frage: Wie rufe ich eine Funktion auf, nachdem die Größe des Browserfensters abgeschlossen wurde (sodass das Ereignis nur einmal ausgelöst wird)?

Sarah
quelle
Siehe diese Antwort: stackoverflow.com/questions/667426/… Es werden Zeitüberschreitungen verwendet, um die Ausführung Ihrer Funktion zu verzögern.
Alastair Pitts
Ich weiß nicht, ob das möglich ist. Sie können dieses Plugin versuchen, obwohl benalman.com/projects/jquery-resize-plugin
BrunoLM
Übrigens ist mir aufgefallen, dass dies in mobilen Browsern sehr nützlich ist, die dazu neigen, die Adressleiste allmählich auszublenden, wenn der Benutzer nach unten scrollt, wodurch die Größe des Bildschirms geändert wird. Ich habe auch erwartet, dass die Größe des Bildschirms nur auf dem Desktop
geändert wird

Antworten:

299

Hier ist eine Modifikation der CMS-Lösung, die an mehreren Stellen in Ihrem Code aufgerufen werden kann:

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

Verwendung:

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

Die Lösung von CMS ist in Ordnung, wenn Sie sie nur einmal aufrufen. Wenn Sie sie jedoch mehrmals aufrufen, z. B. wenn verschiedene Teile Ihres Codes separate Rückrufe für die Fenstergrößenänderung einrichten, schlägt dies fehl, da sie die timerVariable gemeinsam nutzen.

Mit dieser Änderung geben Sie für jeden Rückruf eine eindeutige ID an. Diese eindeutigen IDs werden verwendet, um alle Timeout-Ereignisse getrennt zu halten.

Brahn
quelle
2
I <3 u, ich habe dies kombiniert, während ich die Größe von Vollbild- (nicht HTML5) Highcharts-Diagrammen geändert habe, und funktioniert hervorragend.
Michael J. Calkins
Absolut unglaublich!
Starkers
2
Da ich so sehr von Ihrer Antwort profitiert habe, dachte ich, ich hätte einen funktionierenden Prototyp Ihres bereitgestellten Codes für den Rest der Community freigegeben : jsfiddle.net/h6h2pzpu/3 . Genieße alle!
Jonas Stawski
1
Dies ist alles perfekt, ABER es verzögert die Ausführung der eigentlichen Funktion um die Anzahl der Millisekunden (ms), die SEHR UNERWÜNSCHBAR sein können.
Tomas M
Dies ist einfach perfekt. Gibt es eine Möglichkeit, die letzte Größenänderung zu erfassen und diese Millisekunden nicht weitergeben zu müssen? Sowieso hat das gerade meinen Tag gerettet: ') Danke.
Leo
138

Ich ziehe es vor, eine Veranstaltung zu erstellen:

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

So erstellen Sie es:

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

Sie könnten dies irgendwo in einer globalen Javascript-Datei haben.

Carlos Martinez T.
quelle
Ich habe diese Lösung verwendet. Aber auf lange Sicht möchte ich das Gleiche wie Brahns Lösung implementieren.
Bharat Patil
Dies ermöglicht es Ihnen, sich überall an dieses Ereignis zu binden, nicht nur in einer Funktion, vorausgesetzt, Sie haben mehrere Seiten / .js-Dateien, die natürlich separate Reaktionen erfordern
hanzolo
Dies funktionierte nicht für mich, aber DusanV Antwort hat den Job gemacht
Lightbyte
123

Ich verwende die folgende Funktion, um wiederholte Aktionen zu verzögern. Sie funktioniert für Ihren Fall:

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

Verwendung:

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

Die an sie übergebene Rückruffunktion wird nur ausgeführt, wenn der letzte Aufruf zur Verzögerung nach der angegebenen Zeitspanne erfolgt ist. Andernfalls wird ein Timer zurückgesetzt. Ich finde dies nützlich für andere Zwecke, z. B. zum Erkennen, wann der Benutzer aufgehört hat zu tippen usw. ..

CMS
quelle
5
Ich denke, dieser Ansatz kann fehlschlagen, wenn er mehrmals verwendet wird (z. B. wenn verschiedene Teile des Code-Setups Rückrufe an $(window).resize), weil sie alle die timerVariable gemeinsam nutzen. Siehe meine Antwort unten für die vorgeschlagene Lösung.
Brahn
Sehr schön! Klappt wunderbar! Wie Ihre Antworten ... einfach und elegant!
Herr Kürbis
74

Wenn Sie Underscore.js installiert haben, können Sie:

$(window).resize(_.debounce(function(){
    alert("Resized");
},500));
JT.
quelle
1
Auch wenn Sie Underscore nicht einschließen möchten, holen Sie sich zumindest die Quelle dafür: underscorejs.org/docs/underscore.html#section-67
tybro0103
Debounce ist hier die richtige Technik, es ist nur eine Frage der Implementierung. Und dies ist die überlegene Implementierung, wenn Underscore / Lodash bereits eine Projektabhängigkeit ist.
Factor Mystic
Dies ist jetzt, was ich benutze,
Bharat Patil
20

Einige der zuvor genannten Lösungen haben bei mir nicht funktioniert, obwohl sie allgemeiner sind. Alternativ habe ich diesen gefunden , der den Job bei Fenstergrößenänderung ausgeführt hat:

$(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
quelle
1
Nur dein Beispiel hat für mich funktioniert ... die anderen oben haben es nicht getan! Ich bin nicht sicher, warum Ihre Antwort nicht ausgewählt wurde.
Mumbo Jumbo
Ich verstehe nicht, warum ich das Größenänderungsereignis innerhalb des Größenänderungsereignisses abfangen soll, aber es funktioniert auch für mich ...
Lightbyte
Mumbo Jumbo, ich denke, weil andere sich auf die Verallgemeinerung konzentrieren und nach einer Lösung für ein solches Problem suchen (mehrere Aufrufe einer Funktion).
DusanV
Lightbyte, weil Sie frühere Ereignisse bei jedem Aufruf der Funktion stoppen müssen.
DusanV
13

Vielen Dank an David Walsh, hier ist eine Vanille-Version von 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);
    };
};

Einfache Verwendung:

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

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

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

Irvin Dominin
quelle
6

Wie ich weiß, können Sie einige Aktionen nicht genau dann ausführen, wenn die Größenänderung deaktiviert ist, einfach weil Sie die Aktionen zukünftiger Benutzer nicht kennen. Sie können jedoch davon ausgehen, dass die Zeit zwischen zwei Größenänderungsereignissen vergangen ist. Wenn Sie also etwas länger als diese Zeit warten und keine Größenänderung vorgenommen wird, können Sie Ihre Funktion aufrufen.
Die Idee ist, dass wir verwenden setTimeoutund es ist ID, um es zu speichern oder zu löschen. Zum Beispiel wissen wir, dass die Zeit zwischen zwei Größenänderungsereignissen 500 ms beträgt, daher werden wir 750 ms warten.

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

newint
quelle
3

Global verzögerten Listener deklarieren:

var resize_timeout;

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

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

Und unten verwenden Sie Listener, um resizedEreignisse wie Sie möchten:

$(window).on('resized', function(){
    console.log('resized');
});
gzzz
quelle
Danke, das ist derzeit die beste Lösung. Außerdem habe ich getestet, dass 250 ms beim Ändern der Fenstergröße am besten funktionieren.
AlexioVay
2

Einfaches jQuery-Plugin für Ereignisse mit verzögerter Fenstergröße.

SYNTAX:

Fügen Sie eine neue Funktion hinzu, um die Größe des Ereignisses zu ändern

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

Entfernen Sie die zuvor hinzugefügte Funktion (indem Sie ihre ID deklarieren)

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

Entfernen Sie alle Funktionen

jQuery(window).resizeDelayed( false );

VERWENDUNG:

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

NUTZUNGSAUSGABE:

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ć
quelle
1

Angenommen, der Mauszeiger sollte nach der Größenänderung des Fensters zum Dokument zurückkehren, können wir mit dem Ereignis onmouseover ein rückrufähnliches Verhalten erstellen. Vergessen Sie nicht, dass diese Lösung möglicherweise nicht wie erwartet für Touchscreen-fähige Bildschirme funktioniert.

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
quelle
Gut für mausbasierte Desktop-Sites, aber das Mouseover-Ereignis tritt niemals auf, wenn sich der Benutzer beispielsweise auf einem Mobiltelefon befindet und von Querformat zu Hochformat wechselt oder wenn die Größe des Fensters auf einem Touchscreen-Desktop geändert wird.
user56reinstatemonica8
Sie können die Größe des Browserfensters mithilfe der Tastatur auf den neuesten Windows-Betriebssystemen wie Win-Arrow-Left Win-Arrow-Right usw.
ändern.
0

Folgendes habe ich implementiert:

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

Wir können das setTimeout löschen, wenn wir erwarten, dass die Größenänderung kleiner als ist500ms

Viel Glück...

Akash
quelle