F.Ko-Jiの「一秒後は未来」

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」が出力されているのが分かる。

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

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

著者について

fkoji

F.Ko-Ji

Webエンジニアやってます。最近は ドットインストール の開発がお仕事です。その傍ら、個人で Meity電車遅延なう梅酒.in#グラドル自画撮り部 の部室といったネットサービスを開発・運営してます。梅酒と草野球とリアル脱出ゲームが好きです。

» 詳しいプロフィールや運営サービスの一覧など