jQueryのanimate()によるスクロールなのか手動スクロールなのかをきちんと判別したい
ある要素を自動的にスムーズにスクロールさせたいとき jQueryの animate() を使うことはよくある。例えば 200px だけしゅるしゅるっとスクロールさせたかったら以下のようなコードで可能。
$('#some_el').animate({ scrollTop: 200 }, 450);
ここでもし、あるスクロールが jQuery の animate() による自動スクロールなのか、ユーザーがマウスでスクロールさせたものなのかを判別したかったとする。調べてみると、jQuery の
:animated というセレクタを使うと判別できるらしい。
$('#some_el').on('scroll', function() { if ($(this).is(':animated')) { console.log('Scroll by animate()'); } else { console.log('Scroll by user'); } });
このようにして .is(‘:animated’) が true か false かで判別できる。・・・と思うじゃないですか。ところがコンソールの出力を見てみると、なぜか最後に「Scroll by user」が出力されているのが分かる。
つまり animate() の最後の最後で .is(‘:animated’) は false になってしまっているということ。これだと自動スクロールの最後の最後で手動スクロールが実行されたものと判別されてしまう。
ではどうするか?
ここで animate() にコールバック関数を与えてみる。これは animate() の完了時に呼ばれる。
$('#some_el').animate({ scrollTop: 200 }, 450, function() { console.log('Complete animate()'); });
すると、コールバック関数は「Scroll by user」の出力の直前に実行されていることが分かる。
ということは、完了時のコールバック関数が呼ばれた直後の scroll イベントは animate() によるものということになるので、例えば変数を 1 個用意して、
var animateFinised = false; $('#some_el').animate({ scrollTop: 200 }, 450, function() { animateFinised = true; console.log('Complete animate()'); }); $('#some_el').on('scroll', function() { if (animateFinised) { animateFinised = false; console.log('Scroll by animate()'); } else { if ($(this).is(':animated')) { console.log('Scroll by animate()'); } else { console.log('Scroll by user'); } } });
とすれば、animate() によるスクロールと手動スクロールとをきちんと判別できるようになる。
コメントを残す