DOM は、最初に発生したスクロール イベントと、同じスクロール モーションの一部である後続のイベントを区別する方法を提供しないため、それらを区別する間接的な方法について考える必要があります。
特定の要素をすばやくスクロールすると、スクロール イベントが連続して何度も発生します。次のコードを使用すると、それがどのくらいの頻度で発生するかを正確に把握できます。
$('#exampleDiv').bind('mousewheel', function () {
console.log(new Date().getTime());
});
その div をスクロールすると、次のようなコンソール出力が表示されます。
// Using mouse wheelbar
251327626600149
251327626600215
251327626600265
251327626600282
251327626600332
251327626600365
// Using touchpad
251327626626207
251327626626225
251327626626261
251327626626276
251327626626312
251327626626345
mousescroll
この出力を見ると、イベントは通常、互いに 20 ミリ秒から 60 ミリ秒の間のどこかで発生しているように見えます。安全のために、上限を 100 ミリ秒とします。これは、同じアクションの一部であるスクロール イベントと、ユーザーによって意図的に開始された可能性が高いスクロール イベントとを区別するために使用できるため、非常に有益です。
mousescroll
ここからできることは、グローバルにアクセス可能な「タイムスタンプ」変数を作成し、成功したかどうかにかかわらず、イベントが発生するたびに更新することです。このようなもの:
var timeStamp = new Date().getTime();
$('#exampleDiv').bind('mousewheel', function (event) {
var timeNow = new Date().getTime();
// Need to prevent the default scrolling behavior
event.preventDefault();
// If the last mousescroll happened less that 100 ms ago, update
// timeStamp and do nothing
if (timeNow - timeStamp < 100) {
timeStamp = timeNow;
return;
} else {
timeStamp = timeNow;
scrollToSomeOtherDiv();
}
});
これにより、すべてのイベントの前に発生した最初のイベントの後に発生したすべてのイベントが効果的に無視mousescroll
されますが、ユーザーが 100 ミリ秒一時停止した後に再び機能し始めます。
scrollToSomeOtherDiv()
関数に時間のかかるアニメーションが含まれている場合を除いて、これで問題は解決します。もちろん、グローバルな boolean を作成しisAnimating
、イベントが発生するたびに true かどうmousescroll
かを確認できます (アニメーションが終了したら、コールバックで必ず false にします)。
ユーザーに耳障りな体験を提供する可能性があることを除けば、それは機能します。2 つのパネルをすばやくスクロールしたい人は、アニメーションの開始を見た後でも、スクロール間で一時停止しない可能性があります。上記のコードは、すべてのmousescroll
イベントを同じスクロール モーションの一部として認識し、それらを引き続き無視します。
その場合、アニメーション時間をしきい値として単純に使用できます。アニメーションが開始されたら timeStamp を設定し、mousescroll
その期間中のすべてのイベントを無視します。ここに例を書きました: http://jsfiddle.net/Sg8JQ/
関連するコードは次のとおりです。
var lastAnimation = 0;
var animationTime = 1000; // in ms
var quietPeriod = 500; // in ms, time after animation to ignore mousescroll
function scrollThis(event, delta, deltaX, deltaY) {
var timeNow = new Date().getTime();
// change this to deltaX/deltaY depending on which
// scrolling dir you want to capture
deltaOfInterest = deltaY;
if (deltaOfInterest == 0) {
// Uncomment if you want to use deltaX
// event.preventDefault();
return;
}
// Cancel scroll if currently animating or within quiet period
if(timeNow - lastAnimation < quietPeriod + animationTime) {
event.preventDefault();
return;
}
if (deltaOfInterest < 0) {
if ($('.active').next('div').length) {
lastAnimation = timeNow;
$('.active').removeClass('active').next('div').addClass('active');
$('html,body').animate( {
scrollTop: $('.active').offset().top }, animationTime);
}
} else {
if ($('.active').prev('div').length) {
lastAnimation = timeNow;
$('.active').removeClass('active').prev('div').addClass('active');
$('html,body').animate( {
scrollTop: $('.active').offset().top }, animationTime);
}
}
}
// Note: mousewheel() is defined in the mousewheel plugin by Brandon Aaron
// You could do without it, but you'd need to adjust for firefox and webkit
// separately.
//
// You couldn't use $(document).scroll() because it doesn't allow you to
// preventDefault(), which I use here.
$(document).mousewheel(scrollThis);
また、イベントquietPeriod
を無視し続けたいアニメーション時間を超えた時間も含めました。mousescroll
アニメーションが完了したらすぐにスクロールを「応答」させたい場合は、0 に設定できます。