JavaScript / JQuery: $ (window) .розмір, як запустити ПІСЛЯ завершення зміни розміру?


235

Я використовую JQuery як такий:

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

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

Питання: Як викликати функцію ПІСЛЯ завершення зміни розміру вікна браузера (щоб подія запускалася лише один раз)?


Дивіться цю відповідь: stackoverflow.com/questions/667426/… Він передбачає використання тайм-аутів для затримки виконання вашої функції.
Аластер Піттс

Я не знаю, чи це можливо, ви можете спробувати цей плагін, хоча benalman.com/projects/jquery-resize-plugin
BrunoLM

До речі, я помітив, що це дуже корисно в мобільних браузерах, які, як правило, поступово приховують адресний рядок, коли користувач прокручується вниз, тому змінюючи розмір екрана. Я також очікував, що розмір екрана відбудеться лише на робочому столі ...
MakisH

Відповіді:


299

Ось модифікація рішення 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 чудово, якщо ви викликаєте його лише один раз, але якщо ви називаєте його декілька разів, наприклад, якщо різні частини вашого коду встановлюють окремі зворотні дзвінки для зміни розміру вікна, то вони не зможуть, оскільки вони мають спільну timerзмінну.

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


2
Я <3 u, я поєднав це, змінюючи розмір повноекранного (не html5) графіків з високими діаграмами і чудово працює.
Майкл Дж. Калкінс

Абсолютно неймовірно!
Старкерс

2
Оскільки я отримав велику користь від вашої відповіді, я подумав, що поділився робочим прототипом наданого вами коду для решти спільноти: jsfiddle.net/h6h2pzpu/3 . Радуйте всіх!
Йонас Ставський

1
Це все ідеально, АЛЕ це затримує виконання фактичної функції на кількість мілісекунд (мс), що може бути ДУЖЕ НЕПРАВИЛЬНО.
Томаш М

Це просто ідеально, чи є спосіб захопити останній розмір і не потрібно ретранслируватися на ці мілісекунди? У будь-якому випадку це просто врятувало мені день: ') Дякую.
Лев

138

Я вважаю за краще створити подію:

$(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.


Я використав це рішення. Але в перспективі я хотів би реалізувати те саме, що і рішення Брана.
Бхарат Патіл

це дозволяє вам прив’язуватися до цієї події в усьому світі, а не лише в одній функції, якщо припустимо, що у вас є кілька сторінок / .js файлів, які вимагають окремих реакцій на це, звичайно,
hanzolo

Це не спрацювало для мене, але відповідь Душана зробив цю роботу
lightbyte

123

Я використовую наступну функцію для затримки повторних дій, вона буде працювати у вашому випадку:

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

Використання:

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

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


5
Я думаю, що такий підхід може бути невдалим при використанні декількох разів (наприклад, якщо різні частини відкликання налаштування коду до $(window).resize), оскільки всі вони поділять timerзмінну. Дивіться мою відповідь нижче щодо запропонованого рішення.
brahn

Дуже хороша! Працює як шарм! Як і ваші відповіді ... прості та елегантні!
Містер Гарбуз

74

Якщо у вас встановлено Underscore.js, ви можете:

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

1
Навіть якщо ви не хочете включати підкреслення, принаймні захопіть джерело для цього: underscorejs.org/docs/underscore.html#section-67
tybro0103

Дебюнс - це правильна методика, це лише питання реалізації. І це найкраща реалізація, якщо Underscore / Lodash вже є залежністю від проекту.
Фактор Містик

Це те, що я зараз використовую,
Бхарат Патіл

20

Деякі з вищезгаданих рішень для мене не спрацювали, хоча вони мають загальне використання. Крім того, я знайшов цю, яка виконала роботу з розміром вікна:

$(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
Тільки твій приклад працював на мене ... інші вище не зробили! Я не впевнений, чому ваша відповідь не була обрана.
Mumbo Jumbo

Я не розумію, навіщо ловити подію зміни розміру всередині події зміни розміру, але це працює і для мене ...
lightbyte

Mumbo Jumbo, я думаю, тому що інші фокусуються на узагальненні, шукаючи рішення для будь-якого такого питання (кілька викликів функції).
ДушанВ

lightbyte, це тому, що вам потрібно зупиняти попередні події щоразу, коли функція викликається.
ДушанВ

13

Велике спасибі Девіда Уолша, ось ванільна версія підкреслення дебютації.

Код:

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


6

Насправді, як я знаю, ви не можете виконувати деякі дії саме тоді, коли розмір вимкнено, просто тому, що ви не знаєте дій майбутніх користувачів. Але ви можете припустити, що пройшов час між двома подіями зміни розміру, тому якщо ви зачекаєте трохи більше, ніж цей час, і не буде змінено розмір, ви можете зателефонувати на вашу функцію.
Ідея полягає в тому, що ми використовуємо setTimeoutі id, щоб зберегти або видалити його. Наприклад, ми знаємо, що час між двома подіями зміни розміру становить 500 мс, тому ми будемо чекати 750 мс.

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


3

Оголосити слухача із затримкою у всьому світі:

var resize_timeout;

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

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

А нижче використовуйте слухачів для resizedподії так, як вам потрібно:

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

Дякую, це найкраще рішення на даний момент. Також я перевірив, що 250 мс працює найкращим чином під час зміни вікна.
AlexioVay


2

Простий плагін jQuery для події із затримкою зміни розміру вікна.

SYNTAX:

Додати нову функцію для зміни розміру події

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

ПІДКЛЮЧАТИ:

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

Якщо припустити, що курсор миші повинен повернутися до документа після зміни розміру вікна, ми можемо створити поведінку, що нагадує зворотний виклик, з подією 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);
});

Чудово для сайтів, що працюють лише на настільних комп'ютерах, але подія переходу миші ніколи не відбудеться, якщо, наприклад, користувач перебуває на мобільному телефоні та переходить від пейзажу до портрета, або якщо змінив розмір вікна на робочому столі сенсорного екрана.
користувач56reinstatemonica8

Ви можете змінити розмір вікна браузера за допомогою клавіатури на останніх таких відах, як Win-Arrow-Left Win-Arrow-Right, тощо ...
Lu4,

0

Це те, що я реалізував:

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

ми можемо очистити setTimeout, якщо очікуємо, що розмір стане меншим, ніж500ms

Щасти...

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.