JQuery: Як зателефонувати на подію RESIZE лише після того, як вона закінчена зміною розміру?


109

Як мені викликати функцію, коли вікна браузера закінчили змінити розмір?

Я намагаюся зробити це так, але у мене є проблеми. Я використовую функцію події JQuery Resize:

$(window).resize(function() {
  ... // how to call only once the browser has FINISHED resizing?
});

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

Як я можу викликати функцію зміни розміру лише один раз (після закінчення зміни вікна браузера)?

ОНОВЛЕННЯ

Також без використання глобальної змінної.


@BGerrissen, якщо ти можеш показати мені, як робити jsfiddle.net/Zevan/c9UE5/1 без глобальної змінної, я точно буду :)
nickb

описаний вище метод cleartimeout / settimeout чудово працює.
kris-o3

Відповіді:


129

Ось приклад з використанням інструкцій thejh

Ви можете зберігати ідентифікатор посилання на будь-який набірInterval або setTimeout. Подобається це:

var loop = setInterval(func, 30);

// some time later clear the interval
clearInterval(loop);

Мені подобається, що цей код так просто. Будь-який спосіб зробити цю роботу без використання глобальної змінної?
нік

Якщо я бачу, як це зробити без глобальної змінної, зроблю, що "прийнята відповідь"
nickb

нема проблем. Є кілька способів. Я відредагував відповідь, щоб відобразити найпростіший, про який я міг придумати.
Зеван

дякую за оновлення, але, здається, все ще використовується глобальна змінна. Чи можете ви оновити його, щоб не потрібна глобальна змінна (var id). Дякую
nickb

4
Я думаю, ви пропустили посилання в кінці публікації ... перевірте це: jsfiddle.net/Zevan/c9UE5/5
Zevan

85

Дебанку .

function debouncer( func , timeout ) {
   var timeoutID , timeout = timeout || 200;
   return function () {
      var scope = this , args = arguments;
      clearTimeout( timeoutID );
      timeoutID = setTimeout( function () {
          func.apply( scope , Array.prototype.slice.call( args ) );
      } , timeout );
   }
}


$( window ).resize( debouncer( function ( e ) {
    // do stuff 
} ) );

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

Налаштуйте параметр тайм-ауту для досягнення оптимального ефекту.


1
Я просто спробував запустити це, і, здається, запустити ДВОХ . Я замінив "// робити речі" на "$ (" body "). Append (" <br/> Зроблено! ");" і він називає його
ДВОХ на розмірі

oops ... Я забув досить важливу частину (фактично встановлюючи timeoutID) ... Виправлено зараз, будь ласка, спробуйте ще раз;)
BGerrissen

3
@ user43493: Він називає cuntion func, із внутрішнім thisвказівником, що вказує на scope, і з Array.prototype.slice.call(args)(що генерує стандартний масив поза args) як аргументи
Ерік

4
Це абстракція для багаторазового використання, тому вам не доведеться самостійно обробляти тайм-аути та не відстежувати глобальний timeoutID. Ви можете використовувати його для способу більше, ніж просто зміни розміру вікна;), наприклад, для деблокування кнопки надсилання, передавши більш високий параметр тайм-ауту. Ви можете вибрати рішення з меншим кодом, але я радимо зберегти цей фрагмент у своєму комплекті, ви згодом оціните його;)
BGerrissen

2
Underscore.js чудово реалізує це, якщо ви вже використовуєте цю ліб. underscorejs.org/#debounce
twmulloy

22

Ви можете використовувати setTimeout()і clearTimeout()в поєднанні з jQuery.data:

$(window).resize(function() {
    clearTimeout($.data(this, 'resizeTimer'));
    $.data(this, 'resizeTimer', setTimeout(function() {
        //do something
        alert("Haven't resized in 200ms!");
    }, 200));
});

Оновлення

Я написав розширення, щоб поліпшити jQuery за замовчуванням on(& bind) -event-handler. Він додає функцію обробника подій для однієї або більше подій до вибраних елементів, якщо подія не була запущена протягом заданого інтервалу. Це корисно, якщо ви хочете запустити зворотний дзвінок лише після затримки, як-от подія зміни розміру чи інше. https://github.com/yckart/jquery.unevent.js

;(function ($) {
    var methods = { on: $.fn.on, bind: $.fn.bind };
    $.each(methods, function(k){
        $.fn[k] = function () {
            var args = [].slice.call(arguments),
                delay = args.pop(),
                fn = args.pop(),
                timer;

            args.push(function () {
                var self = this,
                    arg = arguments;
                clearTimeout(timer);
                timer = setTimeout(function(){
                    fn.apply(self, [].slice.call(arg));
                }, delay);
            });

            return methods[k].apply(this, isNaN(delay) ? arguments : args);
        };
    });
}(jQuery));

Використовуйте його як будь-який інший onабо bind-event обробник, за винятком того, що ви можете передавати додатковий параметр як останній:

$(window).on('resize', function(e) {
    console.log(e.type + '-event was 200ms not triggered');
}, 200);

http://jsfiddle.net/ARTsinn/EqqHx/


1
Буквально робіть один і той же пошук Google щодня. і перейти на ту саму сторінку для цього фрагмента коду. Бажаю, я міг би просто згадати це ха-ха.
Дастін Шовк

7
var lightbox_resize = false;
$(window).resize(function() {
    console.log(true);
    if (lightbox_resize)
        clearTimeout(lightbox_resize);
    lightbox_resize = setTimeout(function() {
        console.log('resize');
    }, 500);
});

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

7

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

function registerResize(f) {
    $(window).resize(function() {
        clearTimeout(this.resizeTimeout);
        this.resizeTimeout = setTimeout(function() {
            var oldOverflow = document.body.style.overflow;
            document.body.style.overflow = "hidden";
            var currHeight = $(window).height(),
                currWidth = $(window).width();
            document.body.style.overflow = oldOverflow;

            var prevUndefined = (typeof this.prevHeight === 'undefined' || typeof this.prevWidth === 'undefined');
            if (prevUndefined || this.prevHeight !== currHeight || this.prevWidth !== currWidth) {
                //console.log('Window size ' + (prevUndefined ? '' : this.prevHeight + "," + this.prevWidth) + " -> " + currHeight + "," + currWidth);
                this.prevHeight = currHeight;
                this.prevWidth = currWidth;

                f(currHeight, currWidth);
            }
        }, 200);
    });
    $(window).resize(); // initialize
}

registerResize(function(height, width) {
    // this will be called only once per resize regardless of scrollbars changes
});

див. jsfiddle


5

Underscore.js має кілька чудових методів для цього завдання: throttleі debounce. Навіть якщо ви не використовуєте підкреслення, погляньте на джерело цих функцій. Ось приклад:

var redraw = function() {'redraw logic here'};
var debouncedRedraw = _.debounce(redraw, 750);
$(window).on('resize', debouncedRedraw);

2

Це мій підхід:

document.addEventListener('DOMContentLoaded', function(){
    var tos = {};
    var idi = 0;
    var fn  = function(id)
    {
        var len = Object.keys(tos).length;

        if(len == 0)
            return;

        to = tos[id];
        delete tos[id];

        if(len-1 == 0)
            console.log('Resize finished trigger');
    };

    window.addEventListener('resize', function(){
        idi++;
        var id = 'id-'+idi;
        tos[id] = window.setTimeout(function(){fn(id)}, 500);
    });
});

Слухач розміру події вловлює всі вхідні виклики розміру, створює функцію таймауту для кожного та зберігає ідентифікатор таймауту разом із ітераційним номером, попередньо 'id-'tos слухатель фіксує (для використання в якості ключа масиву) в масиві -array.

кожного разу, коли запускається тайм-аут, він викликає -функцію fn, яка перевіряє, чи це був останній час очікування в tosмасиві (fn-функція видаляє кожен виконаний тайм-аут). якщо true (= if(len-1 == 0)), зміна розміру закінчена.


Було б добре, якби у вас були якісь коментарі чи пояснення, що ви тут робите
Бретт Грегсон

1

jQuery надає offспосіб видалення обробника подій

$(window).resize(function(){
    if(magic == true) {
        $(window).off('resize', arguments.callee);
    }
});
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.