JavaScript / JQuery:$(window).resizeサイズ変更が完了した後に起動する方法?


235

私はJQueryをそのように使用しています:

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

ただし、ウィンドウの端をドラッグしてブラウザウィンドウのサイズを手動で変更し、ウィンドウのサイズを大きくまたは小さくすると、.resize上記のイベントが複数回発生するようです。

質問:ブラウザーウィンドウのサイズ変更が完了した後で(イベントが1回だけ発生するように)関数を呼び出す方法を教えてください。


この回答を参照してください: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のソリューションは、1回だけ呼び出す場合は問題ありませんが、複数回呼び出す場合、たとえば、コードのさまざまな部分がウィンドウのサイズ変更に個別のコールバックを設定する場合、それらはtimer変数を共有して失敗します。

この変更では、コールバックごとに一意のIDを指定し、それらの一意のIDを使用して、すべてのタイムアウトイベントを分離します。


2
私は<3 u、これを組み合わせてフルスクリーン(html5以外)のHighchartsグラフのサイズを変更し、うまく機能しています。
マイケルJ.カルキンス2013年

本当にすごい!
スターカーズ2014年

2
私はあなたの答えから多くの恩恵を受けたので、コミュニティの残りの部分のために提供されたコードの実用的なプロトタイプを共有したと思いました:jsfiddle.net/h6h2pzpu/3。みんなをお楽しみください!
Jonas Stawski、2015

1
これはすべて完璧ですが、実際の関数の実行をミリ秒(ms)だけ遅らせます。これは非常に望ましくない場合があります。
トーマスM

これは完璧です、最後のサイズ変更を取得し、それらのミリ秒をリレーする必要がない方法はありますか?とにかくこれは私の日を救った: ')ありがとう。
レオ、

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ファイルに入れることができます。


このソリューションを使用しました。しかし、長期的には、ブラウンのソリューションと同じものを実装したいと思います。
Bharat Patil 2014

これにより、1つの関数だけでなく、あらゆる場所でそのイベントにバインドできます。もちろん、複数のページ/ .jsファイルに個別の反応が必要な場合
hanzolo

これは私のために動作しませんでしたが、DusanVの答えは仕事をしてくれた
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

非常に素晴らしい!魅力的な作品!あなたの答えのように...シンプルでエレガント!
パンプキン氏2014

74

Underscore.jsがインストールされている場合、次のことができます。

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

1
Underscoreを含めたくない場合でも、少なくともこのソースを
入手してください

ここではデバウンスが正しい手法です。これは実装の問題です。そして、アンダースコア/ロダッシュがすでにプロジェクトの依存関係である場合、これは優れた実装です。
Factor Mystic

これが今使用しているものです
Bharat Patil

20

前述の解決策の一部は、より一般的な使用法ではありますが、うまくいきませんでした。代わりに私がしました。この1見つかったウィンドウのサイズ変更に仕事をしました。

$(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
あなたの例だけが私のために働きました...上の他の人はうまくいきませんでした!なぜあなたの答えが選ばれなかったのか分かりません。
マンボジャンボ2015

resizeイベント内でresizeイベントをキャッチする理由がわかりませんが、それでも
うまくいき

マンボジャンボ、私は他の人が一般化に焦点を当て、そのような問題の解決策(関数の複数の呼び出し)を探しているためと思います。
DusanV

関数が呼び出されるたびに前のイベントを停止する必要があるためです。
DusanV

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

実際、私が知っているように、将来のユーザーのアクションがわからないという理由だけで、サイズ変更がオフになっていると、一部のアクションを正確に実行できません。ただし、2つのサイズ変更イベントの間に経過した時間を想定できるため、この時間より少し長く待ってサイズ変更が行われない場合は、関数を呼び出すことができます。
アイデアは、setTimeout保存または削除するために使用するIDです。たとえば、2つのサイズ変更イベント間の時間は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');
});

おかげで、それは現在最高のソリューションです。また、ウィンドウのサイズを変更するときに250msが最良の方法で機能することをテストしました。
AlexioVay


2

遅延ウィンドウサイズ変更イベント用のシンプルなjQueryプラグイン。

構文:

イベントのサイズを変更する新しい関数を追加する

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

以前に追加された関数を(そのIDを宣言して)削除します

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

マウスベースのデスクトップのみのサイトでは問題ありませんが、たとえば、ユーザーがモバイルで横向きから縦向きに変更したり、タッチスクリーンデスクトップでウィンドウのサイズを変更したりした場合、マウスオーバーイベントは発生しません。
user56reinstatemonica8 2013年

Win-Arrow-Left Win-Arrow-Rightなどの最新のウィンドウでキーボードの助けを借りてブラウザウィンドウのサイズを変更できます...
Lu4

0

これは私が実装したものです:

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

サイズ変更が発生することが予想される場合は、setTimeoutクリアできます。500ms

幸運を...

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.