JavaScript/JQuery: $(window).resize как стрелять ПОСЛЕ изменения размера?

Я использую JQuery как таковой:

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

Однако, похоже, что если пользователь вручную изменяет размеры своих окон браузера, перетаскивая край окна, чтобы сделать его больше/меньше, событие .resize выше срабатывает несколько раз.

Вопрос: Как вызвать функцию ПОСЛЕ изменения размера окна браузера (чтобы событие срабатывало только один раз)?

Ответ 1

Здесь приведена модификация решения CMS, которое можно вызвать в нескольких местах вашего кода:

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

Использование:

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

Решение CMS прекрасно, если вы вызываете его только один раз, но если вы вызываете его несколько раз, например. если разные части кода устанавливают отдельные обратные вызовы для изменения размера окна, тогда он не сможет выполнить b/c, если они разделяют переменную timer.

С помощью этой модификации вы указываете уникальный идентификатор для каждого обратного вызова, и эти уникальные идентификаторы используются для того, чтобы все события таймаута были раздельными.

Ответ 2

Я предпочитаю создавать событие:

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

Вот как вы его создаете:

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

У вас может быть это в глобальном файле javascript где-нибудь.

Ответ 3

Я использую следующую функцию для задержки повторных действий, она будет работать для вашего случая:

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

Использование:

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

Функция обратного вызова, переданная ему, будет выполняться только тогда, когда последний вызов задержки был выполнен по истечении указанного времени, в противном случае таймер будет reset, я считаю это полезным для других целей, таких как обнаружение, когда пользователь прекратил печатать и т.д.

Ответ 4

Если установлен Underscore.js, вы можете:

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

Ответ 5

Некоторые из ранее упомянутых решений не работали для меня, хотя они более общего использования. В качестве альтернативы я нашел этот, который выполнил задание при изменении размера окна:

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

Ответ 6

Большое спасибо Дэвиду Уолшу, вот ванильная версия подчеркивания подчеркивания.

код:

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

Простое использование:

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

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

Ссылка: http://davidwalsh.name/javascript-debounce-function

Ответ 8

На самом деле, как я знаю, вы не можете делать какие-либо действия точно, когда изменение размера отключено, просто потому, что вы не знаете будущих действий пользователя. Но вы можете предположить, что время прошло между двумя событиями изменения размера, поэтому, если вы подождете немного больше, чем на этот раз, и размер не будет изменен, вы можете вызвать свою функцию.
Идея заключается в том, что мы используем setTimeout и его идентификатор, чтобы сохранить или удалить его. Например, мы знаем, что время между двумя событиями изменения размера составляет 500 мс, поэтому мы будем ждать 750 мс.

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

Ответ 9

Простой плагин jQuery для события с изменением размера окна с задержкой.

СИНТАКСИС:

Добавить новую функцию для изменения размера события

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

Удалить ранее добавленную функцию (объявив ее идентификатор)

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

Удалить все функции

jQuery(window).resizeDelayed( false );

ПРИМЕНЕНИЕ:

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

ИСПОЛЬЗОВАНИЕ:

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 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

    }

})();

Ответ 10

Предполагая, что курсор мыши должен вернуться к документу после изменения размера окна, мы можем создать обратное поведение с событием onmouseover. Не забывайте, что это решение может не работать для экранов с сенсорным экраном, как ожидалось.

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

Ответ 12

Посмотрите на эту статью CSS-Tricks. Они используют функцию, называемую debounce. Он выполняется только при прекращении изменения размера окна.

ссылка на статьи CSS-трюки