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() によるスクロールと手動スクロールとをきちんと判別できるようになる。

コメントを残す