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 2013

回答:


129

これは、jhの指示を使用した例です

setIntervalまたはsetTimeoutへの参照IDを保存できます。このような:

var loop = setInterval(func, 30);

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

このコードがとても単純であることを気に入っています。グローバル変数を使用せずにこれを機能させる方法はありますか?
nickb 2010年

グローバル変数なしでこれを行う方法を
見つけたら

問題ない。いくつかの方法があります。私は考えられる最も簡単な答えを反映するように回答を編集しました。
Zevan 2010年

アップデートありがとうございます。それでもグローバル変数を使用しているようです。グローバル変数(var id)を必要としないように更新できますか?ありがとう
nickb 2010年

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
これを実行してみたところ、TWICEが実行されているようです。"// do stuff""$(" body ")。append(" <br/> DONE! ");に置き換えましたブラウザのサイズ変更ではTWICEと呼ばれます
nickb

おっと...かなり重要な部分を忘れてしまいました(実際にはtimeoutIDを設定しています)...修正されました。もう一度やり直してください;)
BGerrissen

3
@ user43493:func内部thisポインターがを指しscopeArray.prototype.slice.call(args)(から標準配列を生成するargs)を引数として
Eric

4
これは再利用可能な抽象概念なので、タイムアウトをハンドコードしたり、グローバルタイムアウトIDを自分で追跡したりする必要はありません。ウィンドウのサイズ変更よりもはるかに多くの方法で使用できます;)たとえば、より高いタイムアウトパラメータを渡して送信ボタンをデバウンスします。より少ないコードソリューションを選択することもできますが、このスニペットをキットに保存することをお勧めします。後でそれを感謝します;)
BGerrissen 2010年

2
Underscore.jsは、すでにそのlibを使用している場合、これを適切に実装しています。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のデフォルトの(&)-event-handlerを拡張する拡張機能を作成しました。イベントが特定の間隔でトリガーされなかった場合、1つ以上のイベントのイベントハンドラー関数を選択した要素にアタッチします。これは、サイズ変更イベントなど、遅延の後にのみコールバックを起動する場合に役立ちます。 https://github.com/yckart/jquery.unevent.jsonbind

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

私はこれが一番好きですが、条件文に中括弧を使用しないのはなぜですか?私はそれがそれらなしで動作しますが、それは見に他の開発者のための痛みを知っている;)
teewuane

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には、このタスクのための2つの優れたメソッドがthrottleありdebounceます。Underscoreを使用していない場合でも、これらの関数のソースを確認してください。次に例を示します。

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

resize-event-listenerは、着信するすべてのサイズ変更呼び出しをキャッチし、それぞれのタイムアウト関数を作成し、-arrayに'id-'(配列キーとして使用できるように)を前に付けた反復番号とともにタイムアウト識別子を保存しtosます。

timoutがトリガーされるたびに、それは-functionを呼び出し、それが配列のfn最後のタイムアウトであったかどうかをチェックしますtos(fn-functionは実行されたすべてのtimoutを削除します)。true(= if(len-1 == 0))の場合、サイズ変更が終了します。


ここで何をしているのかについてコメントや説明があったらいいのですが
Brett Gregson

1

jQueryはoffイベントハンドラーを削除するメソッドを提供します

$(window).resize(function(){
    if(magic == true) {
        $(window).off('resize', arguments.callee);
    }
});
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.