ネットサービスとかGoogleとか豆知識とか。

Index > プログラミング > jQuery > jQueryのanimate()によるスクロールなのか手動スクロールなのかをきちんと判別したい
jQuery
2016年10月16日 00:24

jQueryのanimate()によるスクロールなのか手動スクロールなのかをきちんと判別したい

  • このエントリーをはてなブックマークに追加
  • ... PV
スポンサード リンク

ある要素を自動的にスムーズにスクロールさせたいとき 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」が出力されているのが分かる。

detect-scroll-by-animate-or-manual-01.jpg

つまり animate() の最後の最後で .is(':animated') は false になってしまっているということ。これだと自動スクロールの最後の最後で手動スクロールが実行されたものと判別されてしまう。

ではどうするか?

ここで animate() にコールバック関数を与えてみる。これは animate() の完了時に呼ばれる。

$('#some_el').animate({
    scrollTop: 200
}, 450, function() {
    console.log('Complete animate()');
});

すると、コールバック関数は「Scroll by user」の出力の直前に実行されていることが分かる。

detect-scroll-by-animate-or-manual-02.jpg

ということは、完了時のコールバック関数が呼ばれた直後の 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() によるスクロールと手動スクロールとをきちんと判別できるようになる。

detect-scroll-by-animate-or-manual-03.jpg