由于 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
,并在每次mousescroll
触发事件时检查它是否为真(确保在动画结束后在回调中将其变为假)。
这会奏效,只是它会给用户带来不和谐的体验。即使在看到动画开始后,想要快速滚动浏览两个面板的人也可能不会在滚动之间暂停。上面的代码会将它们的所有mousescroll
事件视为相同滚动动作的一部分,并继续忽略它们!
在这种情况下,您可以简单地使用动画时间作为您的阈值。一旦动画开始,您设置一个时间戳,然后忽略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。